summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/logo-white.pngbin4437 -> 5722 bytes
-rw-r--r--app/assets/images/monokai.pngbin0 -> 6651 bytes
-rw-r--r--app/assets/javascripts/admin.js.coffee41
-rw-r--r--app/assets/javascripts/api.js.coffee1
-rw-r--r--app/assets/javascripts/application.js3
-rw-r--r--app/assets/javascripts/behaviors/toggler_behavior.coffee8
-rw-r--r--app/assets/javascripts/branch-graph.js.coffee119
-rw-r--r--app/assets/javascripts/chart.js.coffee21
-rw-r--r--app/assets/javascripts/commit.js.coffee6
-rw-r--r--app/assets/javascripts/commits.js.coffee7
-rw-r--r--app/assets/javascripts/dashboard.js.coffee83
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee42
-rw-r--r--app/assets/javascripts/extensions/jquery.js.coffee9
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee50
-rw-r--r--app/assets/javascripts/issues.js80
-rw-r--r--app/assets/javascripts/issues.js.coffee72
-rw-r--r--app/assets/javascripts/main.js.coffee21
-rw-r--r--app/assets/javascripts/merge_requests.js.coffee8
-rw-r--r--app/assets/javascripts/pager.js.coffee1
-rw-r--r--app/assets/javascripts/profile.js.coffee6
-rw-r--r--app/assets/javascripts/project.js.coffee41
-rw-r--r--app/assets/javascripts/projects.js.coffee35
-rw-r--r--app/assets/javascripts/search_autocomplete.js.coffee8
-rw-r--r--app/assets/javascripts/team_members.js.coffee6
-rw-r--r--app/assets/javascripts/tree.js.coffee41
-rw-r--r--app/assets/javascripts/wall.js.coffee68
-rw-r--r--app/assets/javascripts/wikis.js.coffee19
-rw-r--r--app/assets/stylesheets/application.scss2
-rw-r--r--app/assets/stylesheets/common.scss161
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/avatar.scss28
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/blocks.scss12
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/buttons.scss4
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/common.scss32
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/files.scss9
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/lists.scss9
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/nav.scss2
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/typography.scss4
-rw-r--r--app/assets/stylesheets/highlight/dark.scss3
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss89
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss3
-rw-r--r--app/assets/stylesheets/highlight/white.scss3
-rw-r--r--app/assets/stylesheets/sections/admin.scss18
-rw-r--r--app/assets/stylesheets/sections/commits.scss36
-rw-r--r--app/assets/stylesheets/sections/dashboard.scss48
-rw-r--r--app/assets/stylesheets/sections/events.scss18
-rw-r--r--app/assets/stylesheets/sections/graph.scss4
-rw-r--r--app/assets/stylesheets/sections/header.scss12
-rw-r--r--app/assets/stylesheets/sections/issues.scss35
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss40
-rw-r--r--app/assets/stylesheets/sections/nav.scss112
-rw-r--r--app/assets/stylesheets/sections/notes.scss37
-rw-r--r--app/assets/stylesheets/sections/profile.scss13
-rw-r--r--app/assets/stylesheets/sections/projects.scss43
-rw-r--r--app/assets/stylesheets/sections/tree.scss2
-rw-r--r--app/assets/stylesheets/sections/votes.scss5
-rw-r--r--app/assets/stylesheets/sections/wall.scss25
-rw-r--r--app/assets/stylesheets/selects.scss10
-rw-r--r--app/assets/stylesheets/themes/ui_basic.scss2
-rw-r--r--app/contexts/commit_load_context.rb1
-rw-r--r--app/contexts/issues/bulk_update_context.rb39
-rw-r--r--app/contexts/issues/list_context.rb32
-rw-r--r--app/contexts/issues_bulk_update_context.rb24
-rw-r--r--app/contexts/issues_list_context.rb30
-rw-r--r--app/contexts/notes/create_context.rb2
-rw-r--r--app/contexts/projects/create_context.rb17
-rw-r--r--app/contexts/projects/fork_context.rb44
-rw-r--r--app/contexts/projects/transfer_context.rb27
-rw-r--r--app/contexts/projects/update_context.rb18
-rw-r--r--app/contexts/search_context.rb21
-rw-r--r--app/controllers/admin/background_jobs_controller.rb4
-rw-r--r--app/controllers/admin/dashboard_controller.rb3
-rw-r--r--app/controllers/admin/groups_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb28
-rw-r--r--app/controllers/admin/resque_controller.rb4
-rw-r--r--app/controllers/admin/teams/members_controller.rb3
-rw-r--r--app/controllers/admin/users_controller.rb6
-rw-r--r--app/controllers/application_controller.rb11
-rw-r--r--app/controllers/blame_controller.rb6
-rw-r--r--app/controllers/blob_controller.rb13
-rw-r--r--app/controllers/commits_controller.rb1
-rw-r--r--app/controllers/compare_controller.rb12
-rw-r--r--app/controllers/dashboard_controller.rb5
-rw-r--r--app/controllers/deploy_keys_controller.rb26
-rw-r--r--app/controllers/edit_tree_controller.rb49
-rw-r--r--app/controllers/files_controller.rb12
-rw-r--r--app/controllers/graph_controller.rb12
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/issues_controller.rb35
-rw-r--r--app/controllers/labels_controller.rb8
-rw-r--r--app/controllers/merge_requests_controller.rb13
-rw-r--r--app/controllers/milestones_controller.rb4
-rw-r--r--app/controllers/notes_controller.rb3
-rw-r--r--app/controllers/notifications_controller.rb21
-rw-r--r--app/controllers/profiles_controller.rb17
-rw-r--r--app/controllers/projects_controller.rb45
-rw-r--r--app/controllers/public/projects_controller.rb1
-rw-r--r--app/controllers/raw_controller.rb25
-rw-r--r--app/controllers/refs_controller.rb40
-rw-r--r--app/controllers/registrations_controller.rb3
-rw-r--r--app/controllers/repositories_controller.rb6
-rw-r--r--app/controllers/search_controller.rb6
-rw-r--r--app/controllers/services_controller.rb19
-rw-r--r--app/controllers/team_members_controller.rb2
-rw-r--r--app/controllers/teams/members_controller.rb3
-rw-r--r--app/controllers/tree_controller.rb42
-rw-r--r--app/controllers/wikis_controller.rb6
-rw-r--r--app/decorators/application_decorator.rb29
-rw-r--r--app/decorators/commit_decorator.rb93
-rw-r--r--app/decorators/event_decorator.rb44
-rw-r--r--app/decorators/tree_decorator.rb33
-rw-r--r--app/decorators/user_decorator.rb11
-rw-r--r--app/helpers/application_helper.rb65
-rw-r--r--app/helpers/commits_helper.rb74
-rw-r--r--app/helpers/events_helper.rb41
-rw-r--r--app/helpers/graph_helper.rb10
-rw-r--r--app/helpers/issues_helper.rb37
-rw-r--r--app/helpers/labels_helper.rb28
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/helpers/notifications_helper.rb2
-rw-r--r--app/helpers/oauth_helper.rb19
-rw-r--r--app/helpers/projects_helper.rb6
-rw-r--r--app/helpers/tree_helper.rb53
-rw-r--r--app/helpers/user_teams_helper.rb1
-rw-r--r--app/mailers/emails/issues.rb12
-rw-r--r--app/mailers/emails/merge_requests.rb17
-rw-r--r--app/mailers/emails/notes.rb1
-rw-r--r--app/models/ability.rb5
-rw-r--r--app/models/campfire_service.rb76
-rw-r--r--app/models/commit.rb200
-rw-r--r--app/models/deploy_key.rb6
-rw-r--r--app/models/deploy_keys_project.rb11
-rw-r--r--app/models/event.rb24
-rw-r--r--app/models/forked_project_link.rb8
-rw-r--r--app/models/gitlab_ci_service.rb27
-rw-r--r--app/models/gollum_wiki.rb17
-rw-r--r--app/models/group.rb1
-rw-r--r--app/models/hipchat_service.rb73
-rw-r--r--app/models/issue.rb19
-rw-r--r--app/models/key.rb17
-rw-r--r--app/models/merge_request.rb55
-rw-r--r--app/models/milestone.rb9
-rw-r--r--app/models/network/commit.rb2
-rw-r--r--app/models/network/graph.rb41
-rw-r--r--app/models/note.rb21
-rw-r--r--app/models/notification.rb39
-rw-r--r--app/models/project.rb114
-rw-r--r--app/models/repository.rb166
-rw-r--r--app/models/service.rb23
-rw-r--r--app/models/tree.rb28
-rw-r--r--app/models/user.rb164
-rw-r--r--app/models/user_team.rb1
-rw-r--r--app/models/users_project.rb20
-rw-r--r--app/models/wiki.rb55
-rw-r--r--app/models/wiki_page.rb4
-rw-r--r--app/observers/activity_observer.rb2
-rw-r--r--app/observers/base_observer.rb9
-rw-r--r--app/observers/issue_observer.rb26
-rw-r--r--app/observers/key_observer.rb7
-rw-r--r--app/observers/merge_request_observer.rb29
-rw-r--r--app/observers/note_observer.rb37
-rw-r--r--app/observers/project_activity_cache_observer.rb8
-rw-r--r--app/observers/project_observer.rb27
-rw-r--r--app/observers/system_hook_observer.rb2
-rw-r--r--app/observers/user_observer.rb11
-rw-r--r--app/observers/users_project_observer.rb9
-rw-r--r--app/services/git_push_service.rb2
-rw-r--r--app/services/notification_service.rb223
-rw-r--r--app/services/project_transfer_service.rb8
-rw-r--r--app/services/system_hooks_service.rb1
-rw-r--r--app/uploaders/attachment_uploader.rb16
-rw-r--r--app/views/admin/background_jobs/show.html.haml (renamed from app/views/admin/resque/show.html.haml)0
-rw-r--r--app/views/admin/dashboard/index.html.haml16
-rw-r--r--app/views/admin/groups/edit.html.haml2
-rw-r--r--app/views/admin/groups/index.html.haml61
-rw-r--r--app/views/admin/groups/new.html.haml4
-rw-r--r--app/views/admin/groups/show.html.haml17
-rw-r--r--app/views/admin/hooks/_data_ex.html.erb8
-rw-r--r--app/views/admin/hooks/index.html.haml2
-rw-r--r--app/views/admin/projects/_form.html.haml86
-rw-r--r--app/views/admin/projects/edit.html.haml3
-rw-r--r--app/views/admin/projects/index.html.haml8
-rw-r--r--app/views/admin/projects/show.html.haml201
-rw-r--r--app/views/admin/projects/team.html.haml0
-rw-r--r--app/views/admin/teams/index.html.haml4
-rw-r--r--app/views/admin/teams/new.html.haml2
-rw-r--r--app/views/admin/teams/show.html.haml14
-rw-r--r--app/views/admin/users/_form.html.haml3
-rw-r--r--app/views/admin/users/index.html.haml3
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/blame/show.html.haml19
-rw-r--r--app/views/blob/_actions.html.haml (renamed from app/views/tree/_blob_actions.html.haml)12
-rw-r--r--app/views/blob/_blob.html.haml32
-rw-r--r--app/views/blob/_download.html.haml (renamed from app/views/tree/blob/_download.html.haml)0
-rw-r--r--app/views/blob/_image.html.haml (renamed from app/views/tree/blob/_image.html.haml)0
-rw-r--r--app/views/blob/_text.html.haml (renamed from app/views/tree/blob/_text.html.haml)0
-rw-r--r--app/views/blob/show.html.haml4
-rw-r--r--app/views/commit/_commit_box.html.haml4
-rw-r--r--app/views/commit/huge_commit.html.haml2
-rw-r--r--app/views/commit/show.html.haml7
-rw-r--r--app/views/commits/_commit.html.haml4
-rw-r--r--app/views/commits/_commits.html.haml3
-rw-r--r--app/views/commits/_diffs.html.haml14
-rw-r--r--app/views/commits/_text_file.html.haml2
-rw-r--r--app/views/commits/show.html.haml6
-rw-r--r--app/views/compare/show.html.haml2
-rw-r--r--app/views/dashboard/_groups.html.haml4
-rw-r--r--app/views/dashboard/_projects.html.haml4
-rw-r--r--app/views/dashboard/_sidebar.html.haml5
-rw-r--r--app/views/dashboard/_teams.html.haml4
-rw-r--r--app/views/dashboard/issues.html.haml7
-rw-r--r--app/views/dashboard/projects.html.haml17
-rw-r--r--app/views/dashboard/show.atom.builder7
-rw-r--r--app/views/dashboard/show.html.haml5
-rw-r--r--app/views/deploy_keys/_deploy_key.html.haml25
-rw-r--r--app/views/deploy_keys/_form.html.haml2
-rw-r--r--app/views/deploy_keys/_show.html.haml12
-rw-r--r--app/views/deploy_keys/index.html.haml41
-rw-r--r--app/views/deploy_keys/show.html.haml2
-rw-r--r--app/views/devise/confirmations/new.html.erb4
-rw-r--r--app/views/devise/mailer/confirmation_instructions.html.erb2
-rw-r--r--app/views/devise/mailer/reset_password_instructions.html.erb2
-rw-r--r--app/views/devise/mailer/unlock_instructions.html.erb2
-rw-r--r--app/views/devise/registrations/edit.html.erb6
-rw-r--r--app/views/devise/sessions/_new_base.html.haml13
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml32
-rw-r--r--app/views/devise/sessions/_oauth_providers.html.haml10
-rw-r--r--app/views/devise/sessions/new.html.haml57
-rw-r--r--app/views/devise/shared/_links.erb4
-rw-r--r--app/views/devise/unlocks/new.html.erb4
-rw-r--r--app/views/edit_tree/show.html.haml (renamed from app/views/tree/edit.html.haml)15
-rw-r--r--app/views/events/_commit.html.haml9
-rw-r--r--app/views/events/_event_push.atom.haml10
-rw-r--r--app/views/events/event/_common.html.haml8
-rw-r--r--app/views/events/event/_push.html.haml4
-rw-r--r--app/views/graph/_head.html.haml16
-rw-r--r--app/views/graph/show.html.haml15
-rw-r--r--app/views/graph/show.json.erb8
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/groups/issues.html.haml2
-rw-r--r--app/views/groups/new.html.haml2
-rw-r--r--app/views/groups/show.atom.builder5
-rw-r--r--app/views/groups/show.html.haml12
-rw-r--r--app/views/help/index.html.haml4
-rw-r--r--app/views/issues/_filter.html.haml2
-rw-r--r--app/views/issues/_form.html.haml62
-rw-r--r--app/views/issues/_issue.html.haml53
-rw-r--r--app/views/issues/_issues.html.haml100
-rw-r--r--app/views/issues/index.html.haml43
-rw-r--r--app/views/issues/index.js.haml4
-rw-r--r--app/views/issues/show.html.haml5
-rw-r--r--app/views/kaminari/admin/_first_page.html.haml9
-rw-r--r--app/views/kaminari/admin/_gap.html.haml9
-rw-r--r--app/views/kaminari/admin/_last_page.html.haml9
-rw-r--r--app/views/kaminari/admin/_next_page.html.haml9
-rw-r--r--app/views/kaminari/admin/_page.html.haml10
-rw-r--r--app/views/kaminari/admin/_paginator.html.haml17
-rw-r--r--app/views/kaminari/admin/_prev_page.html.haml9
-rw-r--r--app/views/kaminari/gitlab/_gap.html.haml5
-rw-r--r--app/views/kaminari/gitlab/_next_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_page.html.haml4
-rw-r--r--app/views/kaminari/gitlab/_paginator.html.haml17
-rw-r--r--app/views/kaminari/gitlab/_prev_page.html.haml2
-rw-r--r--app/views/labels/_label.html.haml18
-rw-r--r--app/views/labels/index.html.haml12
-rw-r--r--app/views/layouts/_google_analytics.html.haml10
-rw-r--r--app/views/layouts/_head.html.haml2
-rw-r--r--app/views/layouts/_head_panel.html.haml7
-rw-r--r--app/views/layouts/_init_auto_complete.html.haml15
-rw-r--r--app/views/layouts/_search.html.haml15
-rw-r--r--app/views/layouts/admin.html.haml24
-rw-r--r--app/views/layouts/application.html.haml25
-rw-r--r--app/views/layouts/group.html.haml25
-rw-r--r--app/views/layouts/nav/_admin.html.haml19
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml20
-rw-r--r--app/views/layouts/nav/_group.html.haml20
-rw-r--r--app/views/layouts/nav/_profile.html.haml17
-rw-r--r--app/views/layouts/nav/_project.html.haml43
-rw-r--r--app/views/layouts/nav/_team.html.haml25
-rw-r--r--app/views/layouts/profile.html.haml20
-rw-r--r--app/views/layouts/project_resource.html.haml50
-rw-r--r--app/views/layouts/user_team.html.haml30
-rw-r--r--app/views/merge_requests/_form.html.haml6
-rw-r--r--app/views/merge_requests/_merge_request.html.haml53
-rw-r--r--app/views/merge_requests/_show.html.haml18
-rw-r--r--app/views/merge_requests/index.html.haml12
-rw-r--r--app/views/merge_requests/show/_commits.html.haml6
-rw-r--r--app/views/merge_requests/show/_diffs.html.haml2
-rw-r--r--app/views/merge_requests/show/_how_to_merge.html.haml23
-rw-r--r--app/views/merge_requests/show/_mr_box.html.haml12
-rw-r--r--app/views/merge_requests/show/_mr_ci.html.haml2
-rw-r--r--app/views/milestones/_milestone.html.haml11
-rw-r--r--app/views/milestones/index.html.haml26
-rw-r--r--app/views/milestones/show.html.haml5
-rw-r--r--app/views/milestones/update.js.haml2
-rw-r--r--app/views/notes/_form.html.haml11
-rw-r--r--app/views/notes/_notes_with_form.html.haml4
-rw-r--r--app/views/notifications/show.html.haml77
-rw-r--r--app/views/notifications/update.js.haml6
-rw-r--r--app/views/notify/closed_issue_email.html.haml5
-rw-r--r--app/views/notify/closed_issue_email.text.haml3
-rw-r--r--app/views/notify/closed_merge_request_email.html.haml9
-rw-r--r--app/views/notify/closed_merge_request_email.text.haml8
-rw-r--r--app/views/notify/merged_merge_request_email.html.haml9
-rw-r--r--app/views/notify/merged_merge_request_email.text.haml8
-rw-r--r--app/views/notify/new_issue_email.html.haml6
-rw-r--r--app/views/notify/new_issue_email.text.erb5
-rw-r--r--app/views/notify/new_ssh_key_email.html.haml2
-rw-r--r--app/views/notify/new_ssh_key_email.text.erb2
-rw-r--r--app/views/notify/new_user_email.html.haml8
-rw-r--r--app/views/notify/new_user_email.text.erb8
-rw-r--r--app/views/profiles/account.html.haml65
-rw-r--r--app/views/profiles/design.html.haml5
-rw-r--r--app/views/profiles/show.html.haml23
-rw-r--r--app/views/projects/_clone_panel.html.haml25
-rw-r--r--app/views/projects/_errors.html.haml4
-rw-r--r--app/views/projects/_form.html.haml139
-rw-r--r--app/views/projects/_new_form.html.haml48
-rw-r--r--app/views/projects/create.js.haml6
-rw-r--r--app/views/projects/edit.html.haml178
-rw-r--r--app/views/projects/empty.html.haml2
-rw-r--r--app/views/projects/new.html.haml61
-rw-r--r--app/views/projects/show.html.haml65
-rw-r--r--app/views/projects/transfer.js.haml7
-rw-r--r--app/views/projects/tree.js.haml5
-rw-r--r--app/views/projects/update.js.haml5
-rw-r--r--app/views/projects/update_failed.js.haml2
-rw-r--r--app/views/protected_branches/index.html.haml2
-rw-r--r--app/views/public/projects/index.html.haml23
-rw-r--r--app/views/refs/logs_tree.js.haml2
-rw-r--r--app/views/repositories/_branch.html.haml3
-rw-r--r--app/views/repositories/_feed.html.haml1
-rw-r--r--app/views/repositories/stats.html.haml26
-rw-r--r--app/views/repositories/tags.html.haml49
-rw-r--r--app/views/search/_blob.html.haml10
-rw-r--r--app/views/search/_filter.html.haml49
-rw-r--r--app/views/search/_result.html.haml19
-rw-r--r--app/views/search/show.html.haml17
-rw-r--r--app/views/services/_form.html.haml48
-rw-r--r--app/views/services/_gitlab_ci.html.haml46
-rw-r--r--app/views/services/edit.html.haml2
-rw-r--r--app/views/services/index.html.haml38
-rw-r--r--app/views/shared/_clone_panel.html.haml15
-rw-r--r--app/views/shared/_merge_requests.html.haml2
-rw-r--r--app/views/shared/_promo.html.haml4
-rw-r--r--app/views/shared/_ref_switcher.html.haml2
-rw-r--r--app/views/snippets/_form.html.haml2
-rw-r--r--app/views/team_members/_assigned_team.html.haml2
-rw-r--r--app/views/team_members/_team.html.haml7
-rw-r--r--app/views/team_members/_team_member.html.haml6
-rw-r--r--app/views/team_members/create.js.haml13
-rw-r--r--app/views/team_members/index.html.haml10
-rw-r--r--app/views/teams/issues.html.haml2
-rw-r--r--app/views/teams/members/_member.html.haml31
-rw-r--r--app/views/teams/members/_show.html.haml30
-rw-r--r--app/views/teams/members/_team.html.haml20
-rw-r--r--app/views/teams/members/index.html.haml26
-rw-r--r--app/views/teams/members/new.html.haml48
-rw-r--r--app/views/teams/show.atom.builder5
-rw-r--r--app/views/teams/show.html.haml12
-rw-r--r--app/views/tree/_blob.html.haml13
-rw-r--r--app/views/tree/_blob_item.html.haml9
-rw-r--r--app/views/tree/_tree.html.haml60
-rw-r--r--app/views/tree/_tree_commit_column.html.haml2
-rw-r--r--app/views/tree/show.js.haml10
-rw-r--r--app/views/votes/_votes_inline.html.haml13
-rw-r--r--app/views/walls/show.html.haml12
-rw-r--r--app/views/wikis/_nav.html.haml4
-rw-r--r--app/views/wikis/_new.html.haml21
-rw-r--r--app/views/wikis/git_access.html.haml4
-rw-r--r--app/views/wikis/history.html.haml5
-rw-r--r--app/views/wikis/pages.html.haml4
-rw-r--r--app/views/wikis/show.html.haml3
-rw-r--r--app/workers/post_receive.rb27
373 files changed, 4446 insertions, 3593 deletions
diff --git a/app/assets/images/logo-white.png b/app/assets/images/logo-white.png
index ecec2405372..a63fb1c9c0a 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.png b/app/assets/images/monokai.png
new file mode 100644
index 00000000000..9477941778e
--- /dev/null
+++ b/app/assets/images/monokai.png
Binary files differ
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index 1dafdf4bd8b..c83b74a76a2 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -1,17 +1,30 @@
-$ ->
- $('input#user_force_random_password').on 'change', (elem) ->
- elems = $('#user_password, #user_password_confirmation')
+class Admin
+ constructor: ->
+ $('input#user_force_random_password').on 'change', (elem) ->
+ elems = $('#user_password, #user_password_confirmation')
- if $(@).attr 'checked'
- elems.val('').attr 'disabled', true
- else
- elems.removeAttr 'disabled'
+ if $(@).attr 'checked'
+ elems.val('').attr 'disabled', true
+ else
+ elems.removeAttr 'disabled'
- $('.log-tabs a').click (e) ->
- e.preventDefault()
- $(this).tab('show')
+ $('.log-tabs a').click (e) ->
+ e.preventDefault()
+ $(this).tab('show')
- $('.log-bottom').click (e) ->
- e.preventDefault()
- visible_log = $(".file_content:visible")
- visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast")
+ $('.log-bottom').click (e) ->
+ e.preventDefault()
+ visible_log = $(".file_content:visible")
+ visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast")
+
+ modal = $('.change-owner-holder')
+
+ $('.change-owner-link').bind "click", ->
+ $(this).hide()
+ modal.show()
+
+ $('.change-owner-cancel-link').bind "click", ->
+ modal.hide()
+ $('.change-owner-link').show()
+
+@Admin = Admin
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index ca721517867..7cac971f247 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -50,4 +50,5 @@
callback(users)
buildUrl: (url) ->
+ url = gon.relative_url_root + url if gon.relative_url_root.present?
return url.replace(':version', gon.api_version)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index adb4009fbc2..ab5fc1b860d 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -14,6 +14,9 @@
//= require jquery.waitforimages
//= require jquery.atwho
//= require jquery.scrollto
+//= require jquery.blockUI
+//= require turbolinks
+//= require jquery.turbolinks
//= require bootstrap
//= require modernizr
//= require chosen-jquery
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.coffee b/app/assets/javascripts/behaviors/toggler_behavior.coffee
index 3fefbf8e121..d2181e7b759 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.coffee
+++ b/app/assets/javascripts/behaviors/toggler_behavior.coffee
@@ -3,3 +3,11 @@ $ ->
container = $(@).closest(".js-toggler-container")
container.toggleClass("on")
+
+ $("body").on "click", ".js-toggle-visibility-link", (e) ->
+ $(@).find('i').
+ toggleClass('icon-chevron-down').
+ toggleClass('icon-chevron-up')
+ container = $(".js-toggle-visibility-container")
+ container.toggleClass("hide")
+ e.preventDefault()
diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee
index 796bebe219a..6e069f264f1 100644
--- a/app/assets/javascripts/branch-graph.js.coffee
+++ b/app/assets/javascripts/branch-graph.js.coffee
@@ -5,10 +5,11 @@ class BranchGraph
@mspace = 0
@parents = {}
@colors = ["#000"]
- @offsetX = 120
+ @offsetX = 150
@offsetY = 20
@unitTime = 30
@unitSpace = 10
+ @prev_start = -1
@load()
load: ->
@@ -24,10 +25,18 @@ class BranchGraph
prepareData: (@days, @commits) ->
@collectParents()
+ @graphHeight = $(@element).height()
+ @graphWidth = $(@element).width()
+ ch = Math.max(@graphHeight, @offsetY + @unitTime * @mtime + 150)
+ cw = Math.max(@graphWidth, @offsetX + @unitSpace * @mspace + 300)
+ @r = Raphael(@element.get(0), cw, ch)
+ @top = @r.set()
+ @barHeight = Math.max(@graphHeight, @unitTime * @days.length + 320)
for c in @commits
c.isParent = true if c.id of @parents
@preparedCommits[c.id] = c
+ @markCommit(c)
@collectColors()
@@ -49,18 +58,12 @@ class BranchGraph
k++
buildGraph: ->
- graphHeight = $(@element).height()
- graphWidth = $(@element).width()
- ch = Math.max(graphHeight, @offsetY + @unitTime * @mtime + 150)
- cw = Math.max(graphWidth, @offsetX + @unitSpace * @mspace + 300)
- @r = r = Raphael(@element.get(0), cw, ch)
- top = r.set()
+ r = @r
cuday = 0
cumonth = ""
- barHeight = Math.max(graphHeight, @unitTime * @days.length + 320)
- r.rect(0, 0, 26, barHeight).attr fill: "#222"
- r.rect(26, 0, 20, barHeight).attr fill: "#444"
+ r.rect(0, 0, 26, @barHeight).attr fill: "#222"
+ r.rect(26, 0, 20, @barHeight).attr fill: "#444"
for day, mm in @days
if cuday isnt day[0]
@@ -81,42 +84,50 @@ class BranchGraph
)
cumonth = day[1]
- for commit in @commits
- x = @offsetX + @unitSpace * (@mspace - commit.space)
- y = @offsetY + @unitTime * commit.time
+ @renderPartialGraph()
+
+ @bindEvents()
- @drawDot(x, y, commit)
+ renderPartialGraph: ->
+ start = Math.floor((@element.scrollTop() - @offsetY) / @unitTime) - 10
+ start = 0 if start < 0
+ end = start + 40
+ end = @commits.length if @commits.length < end
- @drawLines(x, y, commit)
+ if @prev_start == -1 or Math.abs(@prev_start - start) > 10
+ i = start
- @appendLabel(x, y, commit.refs) if commit.refs
+ @prev_start = start
- @appendAnchor(top, commit, x, y)
+ while i < end
+ commit = @commits[i]
+ i += 1
- @markCommit(x, y, commit, graphHeight)
+ if commit.hasDrawn isnt true
+ x = @offsetX + @unitSpace * (@mspace - commit.space)
+ y = @offsetY + @unitTime * commit.time
- top.toFront()
- @bindEvents()
+ @drawDot(x, y, commit)
+
+ @drawLines(x, y, commit)
+
+ @appendLabel(x, y, commit)
+
+ @appendAnchor(x, y, commit)
+
+ commit.hasDrawn = true
+
+ @top.toFront()
bindEvents: ->
drag = {}
element = @element
- dragger = (event) ->
- element.scrollLeft drag.sl - (event.clientX - drag.x)
- element.scrollTop drag.st - (event.clientY - drag.y)
-
- element.on mousedown: (event) ->
- drag =
- x: event.clientX
- y: event.clientY
- st: element.scrollTop()
- sl: element.scrollLeft()
- $(window).on "mousemove", dragger
+
+ $(element).scroll (event) =>
+ @renderPartialGraph()
$(window).on
- mouseup: ->
- $(window).off "mousemove", dragger
- keydown: (event) ->
+ keydown: (event) =>
# left
element.scrollLeft element.scrollLeft() - 50 if event.keyCode is 37
# top
@@ -125,21 +136,24 @@ class BranchGraph
element.scrollLeft element.scrollLeft() + 50 if event.keyCode is 39
# bottom
element.scrollTop element.scrollTop() + 50 if event.keyCode is 40
+ @renderPartialGraph()
+
+ appendLabel: (x, y, commit) ->
+ return unless commit.refs
- appendLabel: (x, y, refs) ->
r = @r
- shortrefs = refs
+ shortrefs = commit.refs
# Truncate if longer than 15 chars
shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17
- text = r.text(x + 8, y, shortrefs).attr(
+ text = r.text(x + 4, y, shortrefs).attr(
"text-anchor": "start"
font: "10px Monaco, monospace"
fill: "#FFF"
- title: refs
+ title: commit.refs
)
textbox = text.getBBox()
# Create rectangle based on the size of the textbox
- rect = r.rect(x, y - 7, textbox.width + 15, textbox.height + 5, 4).attr(
+ rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr(
fill: "#000"
"fill-opacity": .5
stroke: "none"
@@ -156,8 +170,9 @@ class BranchGraph
# Set text to front
text.toFront()
- appendAnchor: (top, commit, x, y) ->
+ appendAnchor: (x, y, commit) ->
r = @r
+ top = @top
options = @options
anchor = r.circle(x, y, 10).attr(
fill: "#000"
@@ -206,22 +221,19 @@ class BranchGraph
# Build line shape
if parent[1] is commit.space
- d1 = [0, 5]
- d2 = [0, 10]
- arrow = "l-2,5,4,0,-2,-5"
+ offset = [0, 5]
+ arrow = "l-2,5,4,0,-2,-5,0,5"
else if parent[1] < commit.space
- d1 = [3, 3]
- d2 = [7, 5]
- arrow = "l5,0,-2,4,-3,-4"
+ offset = [3, 3]
+ arrow = "l5,0,-2,4,-3,-4,4,2"
else
- d1 = [-3, 3]
- d2 = [-7, 5]
- arrow = "l-5,0,2,4,3,-4"
+ offset = [-3, 3]
+ arrow = "l-5,0,2,4,3,-4,-4,2"
# Start point
- route = ["M", x + d1[0], y + d1[1]]
+ route = ["M", x + offset[0], y + offset[1]]
# Add arrow if not first parent
if i > 0
@@ -230,7 +242,6 @@ class BranchGraph
# Circumvent if overlap
if commit.space isnt parentCommit.space or commit.space isnt parent[1]
route.push(
- "L", x + d2[0], y + d2[1],
"L", parentX2, y + 10,
"L", parentX2, parentY - 5,
)
@@ -244,16 +255,18 @@ class BranchGraph
stroke: color
"stroke-width": 2)
- markCommit: (x, y, commit, graphHeight) ->
+ markCommit: (commit) ->
if commit.id is @options.commit_id
r = @r
+ x = @offsetX + @unitSpace * (@mspace - commit.space)
+ y = @offsetY + @unitTime * commit.time
r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr(
fill: "#000"
"fill-opacity": .5
stroke: "none"
)
# Displayed in the center
- @element.scrollTop(y - graphHeight / 2)
+ @element.scrollTop(y - @graphHeight / 2)
Raphael::commitTooltip = (x, y, commit) ->
boxWidth = 300
diff --git a/app/assets/javascripts/chart.js.coffee b/app/assets/javascripts/chart.js.coffee
new file mode 100644
index 00000000000..989f48e5e75
--- /dev/null
+++ b/app/assets/javascripts/chart.js.coffee
@@ -0,0 +1,21 @@
+@Chart =
+ labels: []
+ values: []
+
+ init: (labels, values, title) ->
+ r = Raphael('activity-chart')
+
+ fin = ->
+ @flag = r.popup(@bar.x, @bar.y, @bar.value or "0").insertBefore(this)
+
+ fout = ->
+ @flag.animate
+ opacity: 0, 300, -> @remove()
+
+ r.text(160, 10, title).attr font: "13px sans-serif"
+ r.barchart(
+ 10, 20, 560, 200,
+ [values],
+ {colors:["#456"]}
+ ).label(labels, true)
+ .hover(fin, fout)
diff --git a/app/assets/javascripts/commit.js.coffee b/app/assets/javascripts/commit.js.coffee
new file mode 100644
index 00000000000..9f55a1e6368
--- /dev/null
+++ b/app/assets/javascripts/commit.js.coffee
@@ -0,0 +1,6 @@
+class Commit
+ constructor: ->
+ $('.files .file').each ->
+ new CommitFile(this)
+
+@Commit = Commit
diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee
index 47d6fcf8089..de4c06a2728 100644
--- a/app/assets/javascripts/commits.js.coffee
+++ b/app/assets/javascripts/commits.js.coffee
@@ -23,7 +23,7 @@ class CommitsList
@data.offset = limit
this.initLoadMore()
- this.showProgress();
+ this.showProgress()
@getOld: ->
this.showProgress()
@@ -41,7 +41,8 @@ class CommitsList
else
@disable = true
- @initLoadMore: ->
+ @initLoadMore: ->
+ $(document).unbind('scroll')
$(document).endlessScroll
bottomPixels: 400
fireDelay: 1000
@@ -51,4 +52,4 @@ class CommitsList
callback: =>
this.getOld()
-this.CommitsList = CommitsList \ No newline at end of file
+this.CommitsList = CommitsList
diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee
index 4189c90bbfa..c2fb95ca635 100644
--- a/app/assets/javascripts/dashboard.js.coffee
+++ b/app/assets/javascripts/dashboard.js.coffee
@@ -1,39 +1,44 @@
-window.dashboardPage = ->
- Pager.init 20, true
- initSidebarTab()
- $(".event_filter_link").bind "click", (event) ->
- event.preventDefault()
- toggleFilter $(this)
- reloadActivities()
-
-reloadActivities = ->
- $(".content_list").html ''
- Pager.init 20, true
-
-toggleFilter = (sender) ->
- sender.parent().toggleClass "inactive"
- event_filters = $.cookie("event_filter")
- filter = sender.attr("id").split("_")[0]
- if event_filters
- event_filters = event_filters.split(",")
- else
- event_filters = new Array()
-
- index = event_filters.indexOf(filter)
- if index is -1
- event_filters.push filter
- else
- event_filters.splice index, 1
-
- $.cookie "event_filter", event_filters.join(",")
-
-initSidebarTab = ->
- key = "dashboard_sidebar_filter"
-
- # store selection in cookie
- $('.dash-sidebar-tabs a').on 'click', (e) ->
- $.cookie(key, $(e.target).attr('id'))
-
- # show tab from cookie
- sidebar_filter = $.cookie(key)
- $("#" + sidebar_filter).tab('show') if sidebar_filter
+class Dashboard
+ constructor: ->
+ Pager.init 20, true
+ @initSidebarTab()
+
+ $(".event_filter_link").bind "click", (event) =>
+ event.preventDefault()
+ @toggleFilter($(event.currentTarget))
+ @reloadActivities()
+
+ reloadActivities: ->
+ $(".content_list").html ''
+ Pager.init 20, true
+
+ toggleFilter: (sender) ->
+ sender.parent().toggleClass "inactive"
+ event_filters = $.cookie("event_filter")
+ filter = sender.attr("id").split("_")[0]
+ if event_filters
+ event_filters = event_filters.split(",")
+ else
+ event_filters = new Array()
+
+ index = event_filters.indexOf(filter)
+ if index is -1
+ event_filters.push filter
+ else
+ event_filters.splice index, 1
+
+ $.cookie "event_filter", event_filters.join(","), { path: '/' }
+
+ initSidebarTab: ->
+ key = "dashboard_sidebar_filter"
+
+ # store selection in cookie
+ $('.dash-sidebar-tabs a').on 'click', (e) ->
+ $.cookie(key, $(e.target).attr('id'))
+
+ # show tab from cookie
+ sidebar_filter = $.cookie(key)
+ $("#" + sidebar_filter).tab('show') if sidebar_filter
+
+
+@Dashboard = Dashboard
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
new file mode 100644
index 00000000000..fb149b7f677
--- /dev/null
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -0,0 +1,42 @@
+$ ->
+ new Dispatcher()
+
+class Dispatcher
+ constructor: () ->
+ @initSearch()
+ @initPageScripts()
+
+ initPageScripts: ->
+ page = $('body').attr('data-page')
+ project_id = $('body').attr('data-project-id')
+
+ console.log(page)
+
+ unless page
+ return false
+
+ path = page.split(':')
+
+ switch page
+ when 'issues:index'
+ Issues.init()
+ when 'dashboard:show'
+ new Dashboard()
+ when 'commit:show'
+ new Commit()
+ when 'groups:show', 'teams:show', 'projects:show'
+ Pager.init(20, true)
+ when 'projects:new', 'projects:edit'
+ new Project()
+ when 'walls:show'
+ new Wall(project_id)
+ when 'teams:members:index'
+ new TeamMembers()
+
+ switch path.first()
+ when 'admin' then new Admin()
+ when 'wikis' then new Wikis()
+
+ initSearch: ->
+ autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts')
+ new SearchAutocomplete(autocomplete_json)
diff --git a/app/assets/javascripts/extensions/jquery.js.coffee b/app/assets/javascripts/extensions/jquery.js.coffee
new file mode 100644
index 00000000000..8a997fe318e
--- /dev/null
+++ b/app/assets/javascripts/extensions/jquery.js.coffee
@@ -0,0 +1,9 @@
+$.fn.showAndHide = ->
+ $(@).show().
+ delay(3000).
+ fadeOut()
+
+$.fn.enableButton = ->
+ $(@).removeAttr('disabled').
+ removeClass('disabled')
+
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index 1cc9d34dd80..c8c57b91e03 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -2,37 +2,55 @@
window.GitLab ?= {}
GitLab.GfmAutoComplete =
+ # private_token: ''
+ dataSource: ''
# Emoji
Emoji:
- data: []
+ assetBase: ''
template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
# Team Members
Members:
- data: []
- url: ''
- params:
- private_token: ''
template: '<li data-value="${username}">${username} <small>${name}</small></li>'
+ Issues:
+ template: '<li data-value="${id}"><small>${id}</small> ${title} </li>'
+
# Add GFM auto-completion to all input fields, that accept GFM input.
setup: ->
input = $('.js-gfm-input')
# Emoji
- input.atWho ':',
- data: @Emoji.data
+ input.atwho
+ at: ':'
tpl: @Emoji.template
+ callbacks:
+ before_save: (emojis) =>
+ $.map emojis, (em) => name: em, insert: em+ ':', image: "#{@Emoji.assetBase}/#{em}.png"
# Team Members
- input.atWho '@',
+ input.atwho
+ at: '@'
tpl: @Members.template
- callback: (query, callback) =>
- request_params = $.extend({}, @Members.params, query: query)
- $.getJSON(@Members.url, request_params).done (members) =>
- new_members_data = $.map(members, (m) ->
- username: m.username,
- name: m.name
- )
- callback(new_members_data)
+ search_key: 'search'
+ callbacks:
+ before_save: (members) =>
+ $.map members, (m) => name: m.name, username: m.username, search: "#{m.username} #{m.name}"
+
+ input.atwho
+ at: '#'
+ alias: 'issues'
+ search_key: 'search'
+ tpl: @Issues.template
+ callbacks:
+ before_save: (issues) ->
+ $.map issues, (i) -> id: i.id, title: i.title, search: "#{i.id} #{i.title}"
+ input.one "focus", =>
+ $.getJSON(@dataSource).done (data) ->
+ # load members
+ input.atwho 'load', "@", data.members
+ # load issues
+ input.atwho 'load', "issues", data.issues
+ # load emojis
+ input.atwho 'load', ":", data.emojis
diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js
deleted file mode 100644
index 9ba1a3f1bba..00000000000
--- a/app/assets/javascripts/issues.js
+++ /dev/null
@@ -1,80 +0,0 @@
-function initIssuesSearch() {
- var href = $('#issue_search_form').attr('action');
- var last_terms = '';
-
- $('#issue_search').keyup(function() {
- var terms = $(this).val();
- var milestone_id = $('#milestone_id').val();
- var status = $('#status').val();
-
- if (terms != last_terms) {
- last_terms = terms;
-
- if (terms.length >= 2 || terms.length == 0) {
- $.get(href, { 'status': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) {
- $('#issues-table').html(response);
- });
- }
- }
- });
-}
-
-/**
- * Init issues page
- *
- */
-function issuesPage(){
- initIssuesSearch();
- $("#update_status").chosen();
- $("#update_assignee_id").chosen();
- $("#update_milestone_id").chosen();
-
- $("#label_name").chosen();
- $("#assignee_id").chosen();
- $("#milestone_id").chosen();
- $("#milestone_id, #assignee_id, #label_name").on("change", function(){
- $(this).closest("form").submit();
- });
-
- $('body').on('ajax:success', '.close_issue, .reopen_issue', function(){
- var t = $(this),
- totalIssues,
- reopen = t.hasClass('reopen_issue');
- $('.issue_counter').each(function(){
- var issue = $(this);
- totalIssues = parseInt( $(this).html(), 10 );
-
- if( reopen && issue.closest('.main_menu').length ){
- $(this).html( totalIssues+1 );
- }else {
- $(this).html( totalIssues-1 );
- }
- });
-
- });
-
- $(".check_all_issues").click(function () {
- $('.selected_issue').attr('checked', this.checked);
- issuesCheckChanged();
- });
-
- $('.selected_issue').bind('change', issuesCheckChanged);
-}
-
-function issuesCheckChanged() {
- var checked_issues = $('.selected_issue:checked');
-
- if(checked_issues.length > 0) {
- var ids = []
- $.each(checked_issues, function(index, value) {
- ids.push($(value).attr("data-id"));
- })
- $('#update_issues_ids').val(ids);
- $('.issues_filters').hide();
- $('.issues_bulk_update').show();
- } else {
- $('#update_issues_ids').val([]);
- $('.issues_bulk_update').hide();
- $('.issues_filters').show();
- }
-}
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
new file mode 100644
index 00000000000..67d9498c50a
--- /dev/null
+++ b/app/assets/javascripts/issues.js.coffee
@@ -0,0 +1,72 @@
+@Issues =
+ init: ->
+ Issues.initSearch()
+ Issues.initSelects()
+ Issues.initChecks()
+
+ $("body").on "ajax:success", ".close_issue, .reopen_issue", ->
+ t = $(this)
+ totalIssues = undefined
+ reopen = t.hasClass("reopen_issue")
+ $(".issue_counter").each ->
+ issue = $(this)
+ totalIssues = parseInt($(this).html(), 10)
+ if reopen and issue.closest(".main_menu").length
+ $(this).html totalIssues + 1
+ else
+ $(this).html totalIssues - 1
+ $("body").on "click", ".issues-filters .dropdown-menu a", ->
+ $('.issues-list').block(
+ message: null,
+ overlayCSS:
+ backgroundColor: '#DDD'
+ opacity: .4
+ )
+
+ reload: ->
+ Issues.initSelects()
+ Issues.initChecks()
+ $('#filter_issue_search').val($('#issue_search').val())
+
+ initSelects: ->
+ $("#update_status").chosen()
+ $("#update_assignee_id").chosen()
+ $("#update_milestone_id").chosen()
+ $("#label_name").chosen()
+ $("#assignee_id").chosen()
+ $("#milestone_id").chosen()
+ $("#milestone_id, #assignee_id, #label_name").on "change", ->
+ $(this).closest("form").submit()
+
+ initChecks: ->
+ $(".check_all_issues").click ->
+ $(".selected_issue").attr "checked", @checked
+ Issues.checkChanged()
+
+ $(".selected_issue").bind "change", Issues.checkChanged
+
+
+ initSearch: ->
+ form = $("#issue_search_form")
+ last_terms = ""
+ $("#issue_search").keyup ->
+ terms = $(this).val()
+ unless terms is last_terms
+ last_terms = terms
+ if terms.length >= 2 or terms.length is 0
+ form.submit()
+
+ checkChanged: ->
+ checked_issues = $(".selected_issue:checked")
+ if checked_issues.length > 0
+ ids = []
+ $.each checked_issues, (index, value) ->
+ ids.push $(value).attr("data-id")
+
+ $("#update_issues_ids").val ids
+ $(".issues-filters").hide()
+ $(".issues_bulk_update").show()
+ else
+ $("#update_issues_ids").val []
+ $(".issues_bulk_update").hide()
+ $(".issues-filters").show()
diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee
index b61df846c7a..fd7e296efde 100644
--- a/app/assets/javascripts/main.js.coffee
+++ b/app/assets/javascripts/main.js.coffee
@@ -7,6 +7,8 @@ window.slugify = (text) ->
window.ajaxGet = (url) ->
$.ajax({type: "GET", url: url, dataType: "script"})
+window.showAndHide = (selector) ->
+
window.errorMessage = (message) ->
ehtml = $("<p>")
ehtml.addClass("error_message")
@@ -39,14 +41,31 @@ window.linkify = (str) ->
exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
return str.replace(exp,"<a href='$1'>$1</a>")
+window.simpleFormat = (str) ->
+ linkify(sanitize(str).replace(/\n/g, '<br />'))
+
+window.startSpinner = ->
+ $('.turbolink-spinner').fadeIn()
+
+window.stopSpinner = ->
+ $('.turbolink-spinner').fadeOut()
+
+window.stopEndlessScroll = ->
+ $(document).unbind('scroll')
+
+document.addEventListener("page:fetch", startSpinner)
+document.addEventListener("page:fetch", stopEndlessScroll)
+document.addEventListener("page:receive", stopSpinner)
$ ->
# Click a .one_click_select field, select the contents
$(".one_click_select").on 'click', -> $(@).select()
# Click a .appear-link, appear-data fadeout
- $(".appear-link").on 'click', ->
+ $(".appear-link").on 'click', (e) ->
$('.appear-data').fadeIn()
+ e.preventDefault()
+
# Initialize chosen selects
$('select.chosen').chosen()
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
index 890ca400f81..769a940959b 100644
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ b/app/assets/javascripts/merge_requests.js.coffee
@@ -21,6 +21,13 @@ class MergeRequest
this.initMergeWidget()
this.$('.show-all-commits').on 'click', =>
this.showAllCommits()
+
+ modal = $('#modal_merge_info').modal modal: true, show:false
+
+ $('.how_to_merge_link').bind "click", ->
+ modal.show()
+ $('.modal-header .close').bind "click", ->
+ modal.hide()
# Local jQuery finder
$: (selector) ->
@@ -76,7 +83,6 @@ class MergeRequest
$('.ci_widget.ci-' + state).show()
loadDiff: (event) ->
- $('.dashboard-loader').show()
$.ajax
type: 'GET'
url: this.$('.nav-tabs .diffs-tab a').attr('href')
diff --git a/app/assets/javascripts/pager.js.coffee b/app/assets/javascripts/pager.js.coffee
index 5f606acdf9c..5bd11d273a7 100644
--- a/app/assets/javascripts/pager.js.coffee
+++ b/app/assets/javascripts/pager.js.coffee
@@ -30,6 +30,7 @@
@disable = true
initLoadMore: ->
+ $(document).unbind('scroll')
$(document).endlessScroll
bottomPixels: 400
fireDelay: 1000
diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee
index 42207a390b3..213133bc965 100644
--- a/app/assets/javascripts/profile.js.coffee
+++ b/app/assets/javascripts/profile.js.coffee
@@ -15,6 +15,8 @@ $ ->
$(this).find('.update-failed').hide()
$('.update-username form').on 'ajax:complete', ->
- $(this).find('.save-btn').removeAttr('disabled')
- $(this).find('.save-btn').removeClass('disabled')
+ $(this).find('.btn-save').enableButton()
$(this).find('.loading-gif').hide()
+
+ $('.update-notifications').on 'ajax:complete', ->
+ $(this).find('.btn-save').enableButton()
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
new file mode 100644
index 00000000000..780292daa11
--- /dev/null
+++ b/app/assets/javascripts/project.js.coffee
@@ -0,0 +1,41 @@
+class Project
+ constructor: ->
+ $('.project-edit-container').on 'ajax:before', =>
+ $('.project-edit-container').hide()
+ $('.save-project-loader').show()
+
+ @initEvents()
+
+
+ initEvents: ->
+ disableButtonIfEmptyField '#project_name', '.project-submit'
+
+ $('#project_issues_enabled').change ->
+ if ($(this).is(':checked') == true)
+ $('#project_issues_tracker').removeAttr('disabled')
+ else
+ $('#project_issues_tracker').attr('disabled', 'disabled')
+
+ $('#project_issues_tracker').change()
+
+ $('#project_issues_tracker').change ->
+ if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
+ $('#project_issues_tracker_id').attr('disabled', 'disabled')
+ else
+ $('#project_issues_tracker_id').removeAttr('disabled')
+
+
+@Project = Project
+
+$ ->
+ # Git clone panel switcher
+ scope = $ '.project_clone_holder'
+ if scope.length > 0
+ $('a, button', scope).click ->
+ $('a, button', scope).removeClass 'active'
+ $(@).addClass 'active'
+ $('#project_clone', scope).val $(@).data 'clone'
+
+ # Ref switcher
+ $('.project-refs-select').on 'change', ->
+ $(@).parents('form').submit()
diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee
deleted file mode 100644
index 24106c61b75..00000000000
--- a/app/assets/javascripts/projects.js.coffee
+++ /dev/null
@@ -1,35 +0,0 @@
-window.Projects = ->
- $('.new_project, .edit_project').on 'ajax:before', ->
- $('.project_new_holder, .project_edit_holder').hide()
- $('.save-project-loader').show()
-
- $('form #project_default_branch').chosen()
- disableButtonIfEmptyField '#project_name', '.project-submit'
-
-$ ->
- # Git clone panel switcher
- scope = $ '.project_clone_holder'
- if scope.length > 0
- $('a, button', scope).click ->
- $('a, button', scope).removeClass 'active'
- $(@).addClass 'active'
- $('#project_clone', scope).val $(@).data 'clone'
-
- # Ref switcher
- $('.project-refs-select').on 'change', ->
- $(@).parents('form').submit()
-
- $('#project_issues_enabled').change ->
- if ($(this).is(':checked') == true)
- $('#project_issues_tracker').removeAttr('disabled')
- else
- $('#project_issues_tracker').attr('disabled', 'disabled')
-
- $('#project_issues_tracker').change()
-
- $('#project_issues_tracker').change ->
- if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
- $('#project_issues_tracker_id').attr('disabled', 'disabled')
- else
- $('#project_issues_tracker_id').removeAttr('disabled')
-
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
new file mode 100644
index 00000000000..3418690e109
--- /dev/null
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -0,0 +1,8 @@
+class SearchAutocomplete
+ constructor: (json) ->
+ $("#search").autocomplete
+ source: json
+ select: (event, ui) ->
+ location.href = ui.item.url
+
+@SearchAutocomplete = SearchAutocomplete
diff --git a/app/assets/javascripts/team_members.js.coffee b/app/assets/javascripts/team_members.js.coffee
new file mode 100644
index 00000000000..5eaa8ad4ff9
--- /dev/null
+++ b/app/assets/javascripts/team_members.js.coffee
@@ -0,0 +1,6 @@
+class TeamMembers
+ constructor: ->
+ $('.team-members .project-access-select').on "change", ->
+ $(this.form).submit()
+
+@TeamMembers = TeamMembers
diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee
index 2603b9a96c6..fdc82ff6668 100644
--- a/app/assets/javascripts/tree.js.coffee
+++ b/app/assets/javascripts/tree.js.coffee
@@ -1,40 +1,13 @@
# Code browser tree slider
+# Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
+$(".tree-content-holder .tree-item").live 'click', (e) ->
+ if (e.target.nodeName != "A")
+ path = $('.tree-item-file-name a', this).attr('href')
+ Turbolinks.visit(path)
$ ->
- if $('#tree-slider').length > 0
- # Show the "Loading commit data" for only the first element
- $('span.log_loading:first').removeClass('hide')
-
- $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live "click", ->
- $("#tree-content-holder").hide("slide", { direction: "left" }, 150)
-
- # Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
- $("#tree-slider .tree-item").live 'click', (e) ->
- $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A")
-
- # Maintain forward/back history while browsing the file tree
- ((window) ->
- History = window.History
- $ = window.jQuery
- document = window.document
-
- # Check to see if History.js is enabled for our Browser
- unless History.enabled
- return false
-
- $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
- History.pushState(null, null, decodeURIComponent($(@).attr('href')))
- return false
-
- History.Adapter.bind window, 'statechange', ->
- state = History.getState()
- $.ajax({
- url: state.url,
- dataType: 'script',
- beforeSend: -> $('.tree_progress').addClass("loading"),
- complete: -> $('.tree_progress').removeClass("loading")
- })
- )(window)
+ # Show the "Loading commit data" for only the first element
+ $('span.log_loading:first').removeClass('hide')
# See if there are lines selected
# "#L12" and "#L34-56" supported
diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee
index a35c8c6004e..4f71e6e0c35 100644
--- a/app/assets/javascripts/wall.js.coffee
+++ b/app/assets/javascripts/wall.js.coffee
@@ -1,32 +1,32 @@
-@Wall =
- note_ids: []
- project_id: null
-
- init: (project_id) ->
- Wall.project_id = project_id
- Wall.getContent()
- Wall.initRefresh()
- Wall.initForm()
+class Wall
+ constructor: (project_id) ->
+ @project_id = project_id
+ @note_ids = []
+ @getContent()
+ @initRefresh()
+ @initForm()
#
# Gets an initial set of notes.
#
getContent: ->
- Api.notes Wall.project_id, (notes) ->
- $.each notes, (i, note) ->
+ Api.notes @project_id, (notes) =>
+ $.each notes, (i, note) =>
# render note if it not present in loaded list
# or skip if rendered
- if $.inArray(note.id, Wall.note_ids) == -1
- Wall.note_ids.push(note.id)
- Wall.renderNote(note)
- Wall.scrollDown()
+ if $.inArray(note.id, @note_ids) == -1
+ @note_ids.push(note.id)
+ @renderNote(note)
+ @scrollDown()
$("abbr.timeago").timeago()
initRefresh: ->
- setInterval("Wall.refresh()", 10000)
+ setInterval =>
+ @refresh()
+ , 10000
refresh: ->
- Wall.getContent()
+ @getContent()
scrollDown: ->
notes = $('ul.notes')
@@ -36,8 +36,8 @@
form = $('.wall-note-form')
form.find("#target_type").val('wall')
- form.on 'ajax:success', ->
- Wall.refresh()
+ form.on 'ajax:success', =>
+ @refresh()
form.find(".js-note-text").val("").trigger("input")
form.on 'ajax:complete', ->
@@ -58,14 +58,28 @@
form.show()
renderNote: (note) ->
- author = '<strong class="wall-author">' + note.author.name + '</strong>'
- body = '<span class="wall-text">' + linkify(sanitize(note.body)) + '</span>'
- file = ''
- time = '<abbr class="timeago" title="' + note.created_at + '">' + note.created_at + '</time>'
+ template = @noteTemplate()
+ template = template.replace('{{author_name}}', note.author.name)
+ template = template.replace(/{{created_at}}/g, note.created_at)
+ template = template.replace('{{text}}', simpleFormat(note.body))
if note.attachment
- file = '<span class="wall-file"><a href="/files/note/' + note.id + '/' + note.attachment + '">' + note.attachment + '</a></span>'
-
- html = '<li>' + author + body + file + time + '</li>'
+ file = '<i class="icon-paper-clip"/><a href="/files/note/' + note.id + '/' + note.attachment + '">' + note.attachment + '</a>'
+ else
+ file = ''
+ template = template.replace('{{file}}', file)
+
+
+ $('ul.notes').append(template)
+
+ noteTemplate: ->
+ return '<li>
+ <strong class="wall-author">{{author_name}}</strong>
+ <span class="wall-text">
+ {{text}}
+ <span class="wall-file">{{file}}</span>
+ </span>
+ <abbr class="timeago" title="{{created_at}}">{{created_at}}</abbr>
+ </li>'
- $('ul.notes').append(html)
+@Wall = Wall
diff --git a/app/assets/javascripts/wikis.js.coffee b/app/assets/javascripts/wikis.js.coffee
new file mode 100644
index 00000000000..f2867c8026e
--- /dev/null
+++ b/app/assets/javascripts/wikis.js.coffee
@@ -0,0 +1,19 @@
+class Wikis
+ constructor: ->
+ modal = $('#modal-new-wiki').modal({modal: true, show:false})
+
+ $('.add-new-wiki').bind "click", ->
+ modal.show()
+
+ $('.build-new-wiki').bind "click", ->
+ field = $('#new_wiki_path')
+ slug = field.val()
+ path = field.attr('data-wikis-path')
+
+ if(slug.length > 0)
+ location.href = path + "/" + slug
+
+ $('.modal-header .close').bind "click", ->
+ modal.hide()
+
+@Wikis = Wikis
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index fd15d5c6097..85e43ed0d35 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -36,10 +36,12 @@
@import "sections/admin.scss";
@import "sections/wiki.scss";
@import "sections/wall.scss";
+@import "sections/dashboard.scss";
@import "highlight/white.scss";
@import "highlight/dark.scss";
@import "highlight/solarized_dark.scss";
+@import "highlight/monokai.scss";
/**
* UI themes:
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index 4e7aa968ea7..ccc6f7a9d2d 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -17,7 +17,6 @@ body {
margin: 0 0;
}
-.visible_link,
.author_link {
color: $link_color;
}
@@ -32,30 +31,12 @@ body {
padding-bottom: 0;
}
-.info_link {
- margin-right: 5px;
- float: left;
-
- img {
- width: 20px;
- }
-}
-
-.download_repo_link {
- background: url("images.png") no-repeat 0 -48px;
- padding-left: 20px;
-}
-
table a code {
position: relative;
top: -2px;
margin-right: 3px;
}
-.span12 hr{
- margin-top: 5px;
-}
-
.loading {
margin: 20px auto;
background: url(ajax_loader.gif) no-repeat center center;
@@ -81,10 +62,6 @@ table a code {
}
}
-.git_url_wrapper {
- margin-right:50px
-}
-
span.update-author {
display: block;
color: #999;
@@ -96,37 +73,16 @@ span.update-author {
}
}
-.dashboard-loader {
- float: left;
- margin: 10px;
- display: none;
-}
.user-mention {
color: #2FA0BB;
font-weight: bold;
}
-.neib {
- margin-right: 10px;
-}
-
.label {
- padding: 0px 4px;
- font-size: 10px;
+ padding: 1px 4px;
+ font-size: 12px;
font-style: normal;
- background-color: $link_color;
-
- &.label-success {
- background-color: #8D8;
- color: #333;
- text-shadow: 0 1px 1px white;
- }
-
- &.label-error {
- background-color: #D88;
- color: #333;
- text-shadow: 0 1px 1px white;
- }
+ font-weight: normal;
}
form {
@@ -182,27 +138,6 @@ input[type=text] {
}
}
-.merge-request-form-holder {
- select {
- width: 300px;
- }
-}
-
-/** Issues **/
-#issue_assignee_id {
- width: 300px;
-}
-
-#new_issue_dialog textarea{
- height: 100px;
-}
-
-.project_list_url {
- width: 250px;
- background:#fff !important;
-}
-
-
.line_holder {
&:hover {
td {
@@ -234,24 +169,6 @@ p.time {
margin: 30px 3px 3px 2px;
}
-
-.styled_image {
- border: 2px solid #ddd;
-}
-
-
-
-/* Fix for readme code (stopped it from being yellow) */
-.readme {
- pre {
- background: white !important;
-
- code {
- background: none !important;
- }
- }
-}
-
.search-holder {
label, input {
height: 30px;
@@ -278,6 +195,11 @@ p.time {
top: -5px;
@include border-radius(4px);
+ &.success {
+ background: #4A4;
+ color: #FFF;
+ }
+
&.error {
background: #DA4E49;
color: #FFF;
@@ -345,25 +267,6 @@ li.note {
}
-
-/**
- * Admin area
- *
- */
-.admin_dash {
- .data {
- a {
- h1 {
- line-height: 48px;
- font-size: 48px;
- padding: 20px;
- text-align: center;
- font-weight: normal;
- }
- }
- }
-}
-
.rss-icon {
img {
width: 24px;
@@ -376,24 +279,12 @@ li.note {
}
-
-/* CHZN reset few styles */
-.chzn-container-single .chzn-single {
- background: #FFF;
- border: 1px solid #bbb;
- box-shadow: none;
-}
-.chzn-container-active .chzn-single {
- background: #fff;
-}
-
-
.supp_diff_link,
.show-all-commits {
cursor: pointer;
}
-.merge_request,
+.merge-request,
.issue {
&.today{
background: #EFE;
@@ -493,27 +384,6 @@ pre {
}
}
-.float-link {
- float: left;
- margin-right: 15px;
- .s16 {
- margin-right: 5px;
- }
-}
-
-.dashboard-search-filter {
- padding:5px;
-
- .search-text-input {
- float:left;
- @extend .span2;
- }
- .btn {
- margin-left: 5px;
- float:left;
- }
-}
-
h1.http_status_code {
font-size: 56px;
line-height: 100px;
@@ -544,14 +414,7 @@ img.emoji {
display: none;
}
-.label-branch {
- @include border-radius(4px);
- padding: 2px 4px;
- border: none;
- font-size: 14px;
- background: #474D57;
- color: #fff;
- font-family: $monospace_font;
- text-shadow: 0 1px 1px #111;
- font-weight: normal;
+.chart {
+ overflow: hidden;
+ height: 220px;
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/avatar.scss b/app/assets/stylesheets/gitlab_bootstrap/avatar.scss
index de1fb1551bf..ed6ec77b89b 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/avatar.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/avatar.scss
@@ -1,8 +1,24 @@
-/** AVATARS **/
-img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #ddd; padding: 1px; }
-img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; }
-img.avatar.s24 { width: 24px; height: 24px; margin-right: 8px; }
-img.avatar.s32 { width: 32px; height: 32px; margin-right: 10px; }
-img.avatar.s90 { width: 90px; height: 90px; margin-right: 15px; }
+.avatar {
+ float: left;
+ margin-right: 12px;
+ width: 40px;
+ border: 1px solid #ddd;
+ padding: 1px;
+
+ &.avatar-inline {
+ float: none;
+ margin-left: 3px;
+
+ &.s16 { margin-right: 2px; }
+ &.s24 { margin-right: 2px; }
+ }
+
+ &.s16 { width: 16px; height: 16px; margin-right: 6px; }
+ &.s24 { width: 24px; height: 24px; margin-right: 8px; }
+ &.s32 { width: 32px; height: 32px; margin-right: 10px; }
+ &.s90 { width: 90px; height: 90px; margin-right: 15px; }
+}
+
+
img.lil_av { padding-left: 4px; padding-right: 3px; }
img.small { width: 80px; }
diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
index cb055a1c08b..867920ad08f 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
@@ -13,6 +13,7 @@
background: #F9F9F9;
margin-bottom: 25px;
border: 1px solid #CCC;
+ word-wrap: break-word;
@include solid-shade;
&.ui-box-show {
@@ -41,7 +42,6 @@
.ui-box-body,
.ui-box-bottom {
padding: 15px;
- word-wrap: break-word;
.clearfix {
margin: 0;
@@ -100,8 +100,9 @@
margin-top: 0;
}
- .btn-tiny {
- @include box-shadow(0 0px 0px 1px #f1f1f1);
+ .btn {
+ position: relative;
+ top: -2px;
}
.nav-pills {
@@ -170,3 +171,8 @@
margin: 3px 3px 25px 3px;
}
}
+
+.light-well {
+ background: #f9f9f9;
+ padding: 15px;
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
index 03497e32d26..e9b85686fad 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
@@ -23,7 +23,7 @@
&.disabled {
color: #fff;
- background: #29B;
+ background: $primary_color;
}
}
@@ -39,7 +39,7 @@
&.disabled {
color: #fff;
- background: #29B;
+ background: $primary_color;
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss
index 6bdd1652fd6..d2460c5f022 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/common.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -10,10 +10,17 @@
/** COMMON CLASSES **/
.left { float:left }
-.append-bottom-10 { margin-bottom:10px }
-.append-bottom-20 { margin-bottom:20px }
+
.prepend-top-10 { margin-top:10px }
.prepend-top-20 { margin-top:20px }
+.prepend-left-10 { margin-left:10px }
+.prepend-left-20 { margin-left:20px }
+.append-right-10 { margin-right:10px }
+.append-right-20 { margin-right:20px }
+.append-bottom-10 { margin-bottom:10px }
+.append-bottom-20 { margin-bottom:20px }
+.inline { display: inline-block }
+
.padded { padding:20px }
.ipadded { padding:20px!important }
.lborder { border-left:1px solid #eee }
@@ -31,8 +38,6 @@
border-color: #DDD;
}
-.well { padding: 15px; }
-
/** HELPERS **/
.nothing_here_message {
text-align: center;
@@ -65,15 +70,20 @@ fieldset legend { font-size: 17px; }
/** PAGINATION **/
.gitlab_pagination {
- span a { color: $link_color; }
- .prev, .next, .current, .page a {
- padding: 10px;
- }
- .current {
- border-bottom: 2px solid $style_color;
- }
}
.tab-content {
overflow: visible;
}
+
+@media (max-width: 1200px) {
+ .only-wide {
+ display: none;
+ }
+}
+
+.pagination ul > li > a, .pagination ul > li >span {
+ @include linear-gradient(#f1f1f1, #e1e1e1);
+ color: #333;
+ text-shadow: 0 1px 1px #FFF;
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss
index d0bf3bdd6d3..78a3f0b810d 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/files.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss
@@ -49,6 +49,15 @@
&.wiki {
padding: 20px;
font-size: 13px;
+
+ .highlight {
+ margin-bottom: 9px;
+ @include border-radius(4px);
+
+ > pre {
+ margin: 0;
+ }
+ }
}
&.blob_file {
diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
index 0f893a553ee..e661e02623e 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
@@ -69,5 +69,14 @@ ul.bordered-list {
display: block;
margin: 0px;
&:last-child { border:none }
+
+ &.active {
+ background: #f9f9f9;
+ a { font-weight: bold; }
+ }
+
+ &.light {
+ a { color: #777; }
+ }
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/nav.scss b/app/assets/stylesheets/gitlab_bootstrap/nav.scss
index 2eaef61ca33..0fc8b21de7b 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/nav.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/nav.scss
@@ -16,7 +16,7 @@
padding: 12px;
}
> .active > a {
- border-color: #29B;
+ border-color: $primary_color;
border-radius: 0;
background: #F1F1F1;
color: $style_color;
diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
index 1f0c4802318..ab14624186d 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
@@ -41,6 +41,10 @@ a {
color: $primary_color;
}
+ &:focus {
+ text-decoration: underline;
+ }
+
&.btn {
color: $style_color;
&:hover {
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 4196ea7ad29..a56c98cc5f1 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,4 +1,7 @@
.black .highlight {
+
+ background-color: #333;
+
pre {
background-color: #333;
color: #eee;
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
new file mode 100644
index 00000000000..c9709fa7f12
--- /dev/null
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -0,0 +1,89 @@
+$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 .highlight {
+
+ background-color: #272822;
+
+ pre {
+ background-color: #272822;
+ color: $monokai-fg;
+ }
+
+ .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 */
+}
+
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 3f215b4e0fe..cc82f39ac93 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,4 +1,7 @@
.solarized-dark .highlight {
+
+ background-color: #002B36;
+
pre {
background-color: #002B36;
color: #eee;
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index f200e1d7b60..df127a7c491 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,4 +1,7 @@
.white .highlight {
+
+ background-color: #fff;
+
pre {
background-color: #fff;
color: #333;
diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/sections/admin.scss
index 18b102d7022..e189fd27ac6 100644
--- a/app/assets/stylesheets/sections/admin.scss
+++ b/app/assets/stylesheets/sections/admin.scss
@@ -1,3 +1,21 @@
+/**
+ * Admin area
+ *
+ */
+.admin_dash {
+ .data {
+ a {
+ h1 {
+ line-height: 48px;
+ font-size: 48px;
+ padding: 20px;
+ text-align: center;
+ font-weight: normal;
+ }
+ }
+ }
+}
+
.admin-filter form {
label { width: 110px; }
.controls { margin-left: 130px; }
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index 1e564188892..812587a2ee6 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -99,12 +99,24 @@
}
}
}
+ .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;
+ padding: 0px 0.5em;
border: none;
&.new {
background: #CFD;
@@ -348,7 +360,7 @@
.notes_count {
float: right;
- margin: -6px 8px 6px;
+ margin-right: 10px;
}
code {
@@ -369,19 +381,25 @@
}
.file-stats {
- .new-file{
- i{
+ .new-file {
+ a {
+ color: #090;
+ }
+ i {
color: #1BCF00;
}
}
- .renamed-file{
- i{
+ .renamed-file {
+ i {
color: #FE9300;
}
}
- .deleted-file{
- i{
- color: #FF0000;
+ .deleted-file {
+ a {
+ color: #B00;
+ }
+ i {
+ color: #EE0000;
}
}
.edit-file{
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
new file mode 100644
index 00000000000..9bc4a09a097
--- /dev/null
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -0,0 +1,48 @@
+.dashboard {
+ @extend .row;
+ .activities {
+ }
+
+ .side {
+ @extend .pull-right;
+
+ .ui-box {
+ margin: 3px;
+ > .title {
+ padding: 2px 15px;
+ }
+ .nav-projects-tabs li { padding: 0; }
+ .well-list {
+ li { padding: 15px; }
+ .arrow {
+ float: right;
+ padding: 10px;
+ margin: 0;
+ }
+ .last_activity {
+ padding-top: 5px;
+ display: block;
+ span, strong {
+ font-size: 12px;
+ color: #666;
+ }
+ }
+ }
+ @extend .ui-box;
+ }
+ }
+}
+
+.dashboard-search-filter {
+ padding:5px;
+
+ .search-text-input {
+ float:left;
+ @extend .span2;
+ }
+ .btn {
+ margin-left: 5px;
+ float:left;
+ }
+}
+
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index 94e1d0b609c..e8680dde507 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -35,13 +35,14 @@
.event-title {
color: #333;
font-weight: bold;
+ font-size: 14px;
.author_name {
color: #333;
}
}
.event-body {
.commit p {
- color: #555;
+ color: #666;
padding-top: 5px;
}
.event-info {
@@ -52,6 +53,13 @@
margin-top: 5px;
margin-left: 40px;
+ pre {
+ border: none;
+ background: #f9f9f9;
+ border-radius: 0;
+ color: #555;
+ }
+
.note-file-attach {
.note-image-attach {
margin-top: 4px;
@@ -123,7 +131,7 @@
color: #777;
padding: 10px;
min-height: 22px;
- border-left: 5px solid #5AB9C3;
+ border-left: 5px solid $primary_color;
margin-bottom: 20px;
background: #f9f9f9;
@@ -132,10 +140,10 @@
}
.btn-new-mr {
- @extend .btn-info;
+ @extend .btn-primary;
@extend .small;
@extend .pull-right;
- margin: -3px;
+ margin: -2px;
}
}
@@ -151,7 +159,7 @@
.filter_icon {
a {
text-align:center;
- border-left: 3px solid #29B;
+ border-left: 3px solid $primary_color;
background: #f9f9f9;
margin-bottom: 10px;
float: left;
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss
index 7da00719b33..9be4cb788c1 100644
--- a/app/assets/stylesheets/sections/graph.scss
+++ b/app/assets/stylesheets/sections/graph.scss
@@ -11,9 +11,9 @@
.graph {
background: #f1f1f1;
- cursor: move;
height: 500px;
- overflow: hidden;
+ overflow-y: scroll;
+ overflow-x: hidden;
}
}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index 14e4cef011f..e315b4ebcaa 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -119,8 +119,12 @@ header {
border-bottom: 1px solid #AAA;
.nav > li > a {
- color: #fff;
- text-shadow: 0 1px 0 #111;
+ color: #DDD;
+ text-shadow: 0 1px 0 #444;
+
+ &:hover {
+ color: #FFF;
+ }
}
}
}
@@ -145,7 +149,7 @@ header {
background: url('logo-white.png') no-repeat center 1px;
background-size: 38px;
color: #fff;
- text-shadow: 0 1px 1px #111;
+ text-shadow: 0 1px 1px #444;
}
}
}
@@ -154,7 +158,7 @@ header {
color: #FFF;
}
color: #fff;
- text-shadow: 0 1px 1px #111;
+ text-shadow: 0 1px 1px #444;
}
}
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index 351f2404492..5a1b476fe25 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -1,22 +1,39 @@
-.issues_table {
+.issues-list {
.issue {
padding: 10px;
+ position: relative;
- .issue_check {
+ .issue-title {
+ margin-bottom: 5px;
+ font-size: 14px;
+ }
+
+ .issue-info {
+ color: #999;
+ }
+
+ .issue-check {
float: left;
padding: 8px 0;
padding-right: 8px;
min-width: 15px;
}
- p {
- padding-top: 0;
- padding-bottom: 2px;
+ .issue-labels {
+ display: inline-block;
+ }
+
+ .issue-actions {
+ display: none;
+ position: absolute;
+ top: 10px;
+ right: 2px;
}
- img.avatar {
- width: 32px;
- margin-top: 1px;
+ &:hover {
+ .issue-actions {
+ display: block;
+ }
}
}
}
@@ -60,7 +77,7 @@ input.check_all_issues {
@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } }
@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } }
-#issues-table-holder {
+.issues-holder {
.issues_filters {
}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 4cca0083e44..a84ef71e743 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -53,18 +53,6 @@
}
}
-li.merge_request {
- padding: 10px;
- img.avatar {
- width: 32px;
- margin-top: 1px;
- }
- p {
- padding: 0px;
- padding-bottom: 2px;
- }
-}
-
.merge-in-progress {
@extend .padded;
@extend .append-bottom-10;
@@ -97,3 +85,31 @@ li.merge_request {
.mr_direction_tip {
margin-top:40px
}
+
+.label-branch {
+ @include border-radius(4px);
+ padding: 2px 4px;
+ border: none;
+ font-size: 14px;
+ background: #474D57;
+ color: #fff;
+ font-family: $monospace_font;
+ text-shadow: 0 1px 1px #111;
+ font-weight: normal;
+}
+
+.mr-list {
+ .merge-request {
+ padding: 10px;
+ position: relative;
+
+ .merge-request-title {
+ margin-bottom: 5px;
+ font-size: 14px;
+ }
+
+ .merge-request-info {
+ color: #999;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 50091cd7365..7b7bcf807b5 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -1,68 +1,64 @@
-/*
- * Main Menu of Application
- *
- */
-ul.main_menu {
- margin: auto;
+.main-nav {
margin: 30px 0;
margin-top: 10px;
- height: 38px;
- position: relative;
- overflow: hidden;
- .count {
+ border-bottom: 1px solid #E1E1E1;
+
+ ul {
+ margin: auto;
+ height: 39px;
position: relative;
- top: -1px;
- display: inline-block;
- height: 15px;
- margin: 0 0 0 5px;
- padding: 0 8px 1px 8px;
- height: auto;
- font-size: 0.82em;
- line-height: 14px;
- text-align: center;
- color: #777;
- }
- .label {
- background: $hover;
- text-shadow: none;
- color: $style_color;
- }
- li {
- list-style-type: none;
- margin: 0;
- display: table-cell;
- width: 1%;
- border-bottom: 2px solid #EEE;
- &.active {
- border-bottom: 2px solid #474D57;
- a {
- color: $style_color;
- }
+ top: 3px;
+ overflow: hidden;
+ .count {
+ font-weight: normal;
+ display: inline-block;
+ height: 15px;
+ padding: 1px 6px;
+ height: auto;
+ font-size: 0.82em;
+ line-height: 14px;
+ text-align: center;
+ color: #777;
+ background: #eee;
+ @include border-radius(8px);
+ }
+ .label {
+ background: $hover;
+ text-shadow: none;
+ color: $style_color;
}
+ li {
+ list-style-type: none;
+ margin: 0;
+ display: table-cell;
+ width: 1%;
+ &.active {
+ border-bottom: 3px solid #777;
+ a {
+ color: $style_color;
+ font-weight: bolder;
+ }
+ }
- &.home {
- a {
- i {
- font-size: 20px;
- position: relative;
- top: 4px;
+ &.home {
+ a {
+ i {
+ font-size: 20px;
+ position: relative;
+ top: 4px;
+ }
}
}
}
- }
- a {
- display: block;
- text-align: center;
- font-weight: normal;
- height: 36px;
- line-height: 36px;
- color: #777;
- text-shadow: 0 1px 1px white;
- padding: 0 10px;
+ a {
+ display: block;
+ text-align: center;
+ font-weight: normal;
+ height: 36px;
+ line-height: 34px;
+ color: #777;
+ text-shadow: 0 1px 1px white;
+ padding: 0 10px;
+ }
}
}
-/*
- * End of Main Menu
- *
- */
-
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index ae2e1b258d3..9fe7a24b461 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -1,6 +1,13 @@
/**
* Notes
*/
+
+@-webkit-keyframes target-note {
+ from { background:#fffff0; }
+ 50% { background:#ffffd3; }
+ to { background:#fffff0; }
+}
+
ul.notes {
display: block;
list-style: none;
@@ -91,6 +98,11 @@ ul.notes {
}
}
+ .note:target {
+ -webkit-animation:target-note 2s linear;
+ background: #fffff0;
+ }
+
// paint top or bottom borders depending on notes direction
&:not(.reversed) .note,
&:not(.reversed) .discussion {
@@ -213,7 +225,17 @@ ul.notes {
.reply-btn {
@extend .btn-primary;
}
-.file .content tr.line_holder:hover > td { background: $hover !important; }
+.file .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;
+ }
+}
.file .content tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);
@@ -274,6 +296,15 @@ ul.notes {
}
+.common-note-form {
+ margin: 0;
+ height: 140px;
+ background: #F9F9F9;
+ padding: 3px;
+ padding-bottom: 25px;
+ border: 1px solid #DDD;
+}
+
.note-form-actions {
background: #F9F9F9;
@@ -281,8 +312,8 @@ ul.notes {
padding: 0 5px;
.note-form-option {
- margin-top: 8px;
- margin-left: 15px;
+ margin-top: 10px;
+ margin-left: 30px;
@extend .pull-left;
}
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index 607daf7a97e..c34cd23a9c9 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -20,3 +20,16 @@
border: 1px solid #ddd;
}
}
+
+.save-status-fixed {
+ position: fixed;
+ left: 20px;
+ bottom: 50px;
+}
+
+.update-notifications {
+ margin-bottom: 0;
+ label {
+ margin-bottom: 0;
+ }
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index b6b1423e7d0..22618765eaa 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -1,38 +1,3 @@
-.projects {
- @extend .row;
- .activities {
- }
-
- .side {
- @extend .pull-right;
-
- .ui-box {
- margin: 3px;
- > .title {
- padding: 2px 15px;
- }
- .nav-projects-tabs li { padding: 0; }
- .well-list {
- li { padding: 15px; }
- .arrow {
- float: right;
- padding: 10px;
- margin: 0;
- }
- .last_activity {
- padding-top: 5px;
- display: block;
- span, strong {
- font-size: 12px;
- color: #666;
- }
- }
- }
- @extend .ui-box;
- }
- }
-}
-
.new_project,
.edit_project {
.project_name_holder {
@@ -68,14 +33,6 @@
}
.project_clone_holder {
- input[type="text"],
- .btn {
- font-size: 12px;
- line-height: 18px;
- margin: 0;
- padding: 3px 10px;
- }
-
input[type="text"] {
@extend .monospace;
border: 1px solid #BBB;
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index def440c7134..ffde6aa3fa6 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -97,7 +97,7 @@
.tree-btn-group {
.btn {
- margin-right:-3px;
+ margin-right: 0px;
padding: 2px 10px;
}
}
diff --git a/app/assets/stylesheets/sections/votes.scss b/app/assets/stylesheets/sections/votes.scss
index 4686f5422dc..6c81d9a81b8 100644
--- a/app/assets/stylesheets/sections/votes.scss
+++ b/app/assets/stylesheets/sections/votes.scss
@@ -35,9 +35,4 @@
.votes-inline {
display: inline-block;
margin: 0 8px;
- .progress {
- display: inline-block;
- padding: 0 0 2px;
- width: 45px;
- }
}
diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss
index 598d9df8a6a..d6ac08fcf6f 100644
--- a/app/assets/stylesheets/sections/wall.scss
+++ b/app/assets/stylesheets/sections/wall.scss
@@ -14,12 +14,31 @@
.notes {
margin-bottom: 160px;
+ background: #FFE;
+ border: 1px solid #EED;
+
+ > li {
+ @extend .clearfix;
+ border-bottom: 1px solid #EED;
+ padding: 10px;
+ }
.wall-author {
color: #666;
- margin-right: 10px;
- border-right: 1px solid #CCC;
- padding-right: 5px
+ float: left;
+ font-size: 12px;
+ width: 120px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .wall-text {
+ border-left: 1px solid #CCC;
+ margin-left: 10px;
+ padding-left: 10px;
+ float: left;
+ width: 75%;
}
.wall-file {
diff --git a/app/assets/stylesheets/selects.scss b/app/assets/stylesheets/selects.scss
index 07f7db75ffc..7abbe80bd39 100644
--- a/app/assets/stylesheets/selects.scss
+++ b/app/assets/stylesheets/selects.scss
@@ -1,3 +1,13 @@
+/* CHZN reset few styles */
+.chzn-container-single .chzn-single {
+ background: #FFF;
+ border: 1px solid #bbb;
+ box-shadow: none;
+}
+.chzn-container-active .chzn-single {
+ background: #fff;
+}
+
.ajax-users-select {
width: 400px;
}
diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss
index 4e34e8b1b6b..b0ee94ef34a 100644
--- a/app/assets/stylesheets/themes/ui_basic.scss
+++ b/app/assets/stylesheets/themes/ui_basic.scss
@@ -5,7 +5,7 @@
*/
.ui_basic {
.separator {
- background: white;
+ background: #F9F9F9;
border-left: 1px solid #DDD;
}
}
diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb
index 1f23f633af3..2cf5420d62d 100644
--- a/app/contexts/commit_load_context.rb
+++ b/app/contexts/commit_load_context.rb
@@ -12,7 +12,6 @@ class CommitLoadContext < BaseContext
commit = project.repository.commit(params[:id])
if commit
- commit = CommitDecorator.decorate(commit)
line_notes = project.notes.for_commit_id(commit.id).inline
result[:commit] = commit
diff --git a/app/contexts/issues/bulk_update_context.rb b/app/contexts/issues/bulk_update_context.rb
new file mode 100644
index 00000000000..73a3c353523
--- /dev/null
+++ b/app/contexts/issues/bulk_update_context.rb
@@ -0,0 +1,39 @@
+module Issues
+ class BulkUpdateContext < BaseContext
+ def execute
+ update_data = params[:update]
+
+ issues_ids = update_data[:issues_ids].split(",")
+ milestone_id = update_data[:milestone_id]
+ assignee_id = update_data[:assignee_id]
+ status = update_data[:status]
+
+ new_state = nil
+
+ if status.present?
+ if status == 'closed'
+ new_state = :close
+ else
+ new_state = :reopen
+ end
+ end
+
+ opts = {}
+ opts[:milestone_id] = milestone_id if milestone_id.present?
+ opts[:assignee_id] = assignee_id if assignee_id.present?
+
+ issues = Issue.where(id: issues_ids).all
+ issues = issues.select { |issue| can?(current_user, :modify_issue, issue) }
+
+ issues.each do |issue|
+ issue.update_attributes(opts)
+ issue.send new_state if new_state
+ end
+
+ {
+ count: issues.count,
+ success: !issues.count.zero?
+ }
+ end
+ end
+end
diff --git a/app/contexts/issues/list_context.rb b/app/contexts/issues/list_context.rb
new file mode 100644
index 00000000000..a35bddd6443
--- /dev/null
+++ b/app/contexts/issues/list_context.rb
@@ -0,0 +1,32 @@
+module Issues
+ class ListContext < BaseContext
+ include IssuesHelper
+
+ attr_accessor :issues
+
+ def execute
+ @issues = case params[:status]
+ when issues_filter[:all] then @project.issues
+ when issues_filter[:closed] then @project.issues.closed
+ when issues_filter[:to_me] then @project.issues.assigned(current_user)
+ when issues_filter[:by_me] then @project.issues.authored(current_user)
+ else @project.issues.opened
+ 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
+
+ @issues
+ end
+ end
+end
diff --git a/app/contexts/issues_bulk_update_context.rb b/app/contexts/issues_bulk_update_context.rb
deleted file mode 100644
index 7c3c1d4f7c3..00000000000
--- a/app/contexts/issues_bulk_update_context.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-class IssuesBulkUpdateContext < BaseContext
- def execute
- update_data = params[:update]
-
- issues_ids = update_data[:issues_ids].split(",")
- milestone_id = update_data[:milestone_id]
- assignee_id = update_data[:assignee_id]
- status = update_data[:status]
-
- opts = {}
- opts[:milestone_id] = milestone_id if milestone_id.present?
- opts[:assignee_id] = assignee_id if assignee_id.present?
- opts[:closed] = (status == "closed") if status.present?
-
- issues = Issue.where(id: issues_ids).all
- issues = issues.select { |issue| can?(current_user, :modify_issue, issue) }
- issues.each { |issue| issue.update_attributes(opts) }
- {
- count: issues.count,
- success: !issues.count.zero?
- }
- end
-end
-
diff --git a/app/contexts/issues_list_context.rb b/app/contexts/issues_list_context.rb
deleted file mode 100644
index 0765b30c354..00000000000
--- a/app/contexts/issues_list_context.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class IssuesListContext < BaseContext
- include IssuesHelper
-
- attr_accessor :issues
-
- def execute
- @issues = case params[:status]
- when issues_filter[:all] then @project.issues
- when issues_filter[:closed] then @project.issues.closed
- when issues_filter[:to_me] then @project.issues.assigned(current_user)
- when issues_filter[:by_me] then @project.issues.authored(current_user)
- else @project.issues.opened
- 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
-
- @issues
- end
-end
diff --git a/app/contexts/notes/create_context.rb b/app/contexts/notes/create_context.rb
index 1367dff4699..36ea76ff949 100644
--- a/app/contexts/notes/create_context.rb
+++ b/app/contexts/notes/create_context.rb
@@ -3,8 +3,6 @@ module Notes
def execute
note = project.notes.new(params[:note])
note.author = current_user
- note.notify = params[:notify].present?
- note.notify_author = params[:notify_author].present?
note.save
note
end
diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb
index 56c4e1c51da..2922564ba20 100644
--- a/app/contexts/projects/create_context.rb
+++ b/app/contexts/projects/create_context.rb
@@ -8,7 +8,18 @@ module Projects
# get namespace id
namespace_id = params.delete(:namespace_id)
- @project = Project.new(params)
+ # Load default feature settings
+ default_features = Gitlab.config.gitlab.default_projects_features
+
+ default_opts = {
+ issues_enabled: default_features.issues,
+ wiki_enabled: default_features.wiki,
+ wall_enabled: default_features.wall,
+ snippets_enabled: default_features.snippets,
+ merge_requests_enabled: default_features.merge_requests
+ }
+
+ @project = Project.new(default_opts.merge(params))
# Parametrize path for project
#
@@ -32,10 +43,6 @@ module Projects
@project.namespace_id = current_user.namespace_id
end
- # Disable less important features by default
- @project.wall_enabled = false
- @project.snippets_enabled = false
-
@project.creator = current_user
# Import project from cloneable resource
diff --git a/app/contexts/projects/fork_context.rb b/app/contexts/projects/fork_context.rb
new file mode 100644
index 00000000000..fbc67220d5d
--- /dev/null
+++ b/app/contexts/projects/fork_context.rb
@@ -0,0 +1,44 @@
+module Projects
+ class ForkContext < BaseContext
+ include Gitlab::ShellAdapter
+
+ def initialize(project, user)
+ @from_project, @current_user = project, user
+ end
+
+ def execute
+ project = @from_project.dup
+ project.name = @from_project.name
+ project.path = @from_project.path
+ project.namespace = current_user.namespace
+ project.creator = current_user
+
+ # If the project cannot save, we do not want to trigger the project destroy
+ # as this can have the side effect of deleting a repo attached to an existing
+ # project with the same name and namespace
+ if project.valid?
+ begin
+ Project.transaction do
+ #First save the DB entries as they can be rolled back if the repo fork fails
+ project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id)
+ if project.save
+ project.users_projects.create(project_access: UsersProject::MASTER, user: current_user)
+ end
+ #Now fork the repo
+ unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path)
+ raise "forking failed in gitlab-shell"
+ end
+ project.ensure_satellite_exists
+ end
+ rescue => ex
+ project.errors.add(:base, "Fork transaction failed.")
+ project.destroy
+ end
+ else
+ project.errors.add(:base, "Invalid fork destination")
+ end
+ project
+
+ end
+ end
+end
diff --git a/app/contexts/projects/transfer_context.rb b/app/contexts/projects/transfer_context.rb
new file mode 100644
index 00000000000..aed396a5da5
--- /dev/null
+++ b/app/contexts/projects/transfer_context.rb
@@ -0,0 +1,27 @@
+module Projects
+ class TransferContext < BaseContext
+ def execute(role = :default)
+ namespace_id = params[:project].delete(:namespace_id)
+ allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
+
+ if allowed_transfer && namespace_id.present?
+ if namespace_id == Namespace.global_id
+ if project.namespace.present?
+ # Transfer to global namespace from anyone
+ project.transfer(nil)
+ end
+ elsif namespace_id.to_i != project.namespace_id
+ # Transfer to someone namespace
+ namespace = Namespace.find(namespace_id)
+ project.transfer(namespace)
+ end
+ end
+
+ rescue ProjectTransferService::TransferError => ex
+ project.reload
+ project.errors.add(:namespace_id, ex.message)
+ false
+ end
+ end
+end
+
diff --git a/app/contexts/projects/update_context.rb b/app/contexts/projects/update_context.rb
index e5d09b7df7f..40385fa65b0 100644
--- a/app/contexts/projects/update_context.rb
+++ b/app/contexts/projects/update_context.rb
@@ -1,24 +1,8 @@
module Projects
class UpdateContext < BaseContext
def execute(role = :default)
- namespace_id = params[:project].delete(:namespace_id)
+ params[:project].delete(:namespace_id)
params[:project].delete(:public) unless can?(current_user, :change_public_mode, project)
-
- allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
-
- if allowed_transfer && namespace_id.present?
- if namespace_id == Namespace.global_id
- if project.namespace.present?
- # Transfer to global namespace from anyone
- project.transfer(nil)
- end
- elsif namespace_id.to_i != project.namespace_id
- # Transfer to someone namespace
- namespace = Namespace.find(namespace_id)
- project.transfer(namespace)
- end
- end
-
project.update_attributes(params[:project], as: role)
end
end
diff --git a/app/contexts/search_context.rb b/app/contexts/search_context.rb
index 9becb8d674f..22cda709f69 100644
--- a/app/contexts/search_context.rb
+++ b/app/contexts/search_context.rb
@@ -10,10 +10,19 @@ class SearchContext
return result unless query.present?
- result[:projects] = Project.where(id: project_ids).search(query).limit(10)
- result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10)
- result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
- result[:wiki_pages] = Wiki.where(project_id: project_ids).search(query).limit(10)
+ projects = Project.where(id: project_ids)
+ result[:projects] = projects.search(query).limit(10)
+
+ # Search inside singe project
+ project = projects.first if projects.length == 1
+
+ if params[:search_code].present?
+ result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo?
+ else
+ result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10)
+ result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
+ result[:wiki_pages] = []
+ end
result
end
@@ -22,8 +31,8 @@ class SearchContext
projects: [],
merge_requests: [],
issues: [],
- wiki_pages: []
+ wiki_pages: [],
+ blobs: []
}
end
end
-
diff --git a/app/controllers/admin/background_jobs_controller.rb b/app/controllers/admin/background_jobs_controller.rb
new file mode 100644
index 00000000000..994e707965a
--- /dev/null
+++ b/app/controllers/admin/background_jobs_controller.rb
@@ -0,0 +1,4 @@
+class Admin::BackgroundJobsController < Admin::ApplicationController
+ def show
+ end
+end
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 3c27b86180b..3c80b6503fa 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -2,8 +2,5 @@ class Admin::DashboardController < Admin::ApplicationController
def index
@projects = Project.order("created_at DESC").limit(10)
@users = User.order("created_at DESC").limit(10)
-
- rescue Redis::InheritedError
- @resque_accessible = false
end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index f552fb595b8..df520bea773 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -69,7 +69,7 @@ class Admin::GroupsController < Admin::ApplicationController
def project_teams_update
@group.add_users_to_project_teams(params[:user_ids], params[:project_access])
- redirect_to [:admin, @group], notice: 'Users was successfully added.'
+ redirect_to [:admin, @group], notice: 'Users were successfully added.'
end
def destroy
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 8ae0bba9a2d..bbb80cbb839 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -19,34 +19,6 @@ class Admin::ProjectsController < Admin::ApplicationController
@users = @users.all
end
- def edit
- end
-
- def team_update
- @project.team.add_users_ids(params[:user_ids], params[:project_access])
-
- redirect_to [:admin, @project], notice: 'Project was successfully updated.'
- end
-
- def update
- project.creator = current_user unless project.creator
-
- status = ::Projects::UpdateContext.new(project, current_user, params).execute(:admin)
-
- if status
- redirect_to [:admin, @project], notice: 'Project was successfully updated.'
- else
- render action: "edit"
- end
- end
-
- def destroy
- @project.team.truncate
- @project.destroy
-
- redirect_to admin_projects_path, notice: 'Project was successfully deleted.'
- end
-
protected
def project
diff --git a/app/controllers/admin/resque_controller.rb b/app/controllers/admin/resque_controller.rb
deleted file mode 100644
index 7d489ab4876..00000000000
--- a/app/controllers/admin/resque_controller.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class Admin::ResqueController < Admin::ApplicationController
- def show
- end
-end
diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb
index e6469874419..590617f67c9 100644
--- a/app/controllers/admin/teams/members_controller.rb
+++ b/app/controllers/admin/teams/members_controller.rb
@@ -1,7 +1,6 @@
class Admin::Teams::MembersController < Admin::Teams::ApplicationController
def new
@users = User.potential_team_members(user_team)
- @users = UserDecorator.decorate_collection @users
end
def create
@@ -12,7 +11,7 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController
user_team.add_members(user_ids, access, is_admin)
end
- redirect_to admin_team_path(user_team), notice: 'Members was successfully added into Team of users.'
+ redirect_to admin_team_path(user_team), notice: 'Members were successfully added into Team of users.'
end
def edit
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 43e6f09904f..185ad181b2a 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -14,7 +14,7 @@ class Admin::UsersController < Admin::ApplicationController
@not_in_projects = @not_in_projects.without_user(admin_user) if admin_user.authorized_projects.present?
# Projects he already own or joined
- @projects = admin_user.authorized_projects.where('projects.id in (?)', admin_user.authorized_projects.map(&:id))
+ @projects = admin_user.authorized_projects
end
def team_update
@@ -29,7 +29,7 @@ class Admin::UsersController < Admin::ApplicationController
def new
- @admin_user = User.new({ projects_limit: Gitlab.config.gitlab.default_projects_limit }, as: :admin)
+ @admin_user = User.new.with_defaults
end
def edit
@@ -84,6 +84,8 @@ class Admin::UsersController < Admin::ApplicationController
format.html { redirect_to [:admin, admin_user], notice: 'User was successfully updated.' }
format.json { head :ok }
else
+ # restore username to keep form action url.
+ admin_user.username = params[:id]
format.html { render action: "edit" }
format.json { render json: admin_user.errors, status: :unprocessable_entity }
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 32b1246601d..9bb86b80d1e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -32,7 +32,7 @@ class ApplicationController < ActionController::Base
def reject_blocked!
if current_user && current_user.blocked?
sign_out current_user
- flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
+ flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
redirect_to new_user_session_path
end
end
@@ -40,7 +40,7 @@ class ApplicationController < ActionController::Base
def after_sign_in_path_for resource
if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
sign_out resource
- flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
+ flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
new_user_session_path
else
super
@@ -69,7 +69,7 @@ class ApplicationController < ActionController::Base
@project
else
@project = nil
- render_404
+ render_404 and return
end
end
@@ -88,7 +88,7 @@ class ApplicationController < ActionController::Base
end
def authorize_code_access!
- return access_denied! unless can?(current_user, :download_code, project)
+ return access_denied! unless can?(current_user, :download_code, project) or project.public?
end
def authorize_create_team!
@@ -152,8 +152,9 @@ class ApplicationController < ActionController::Base
def add_gon_variables
gon.default_issues_tracker = Project.issues_tracker.default_value
- gon.api_version = Gitlab::API.version
+ gon.api_version = API::API.version
gon.api_token = current_user.private_token if current_user
gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
+ gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
end
end
diff --git a/app/controllers/blame_controller.rb b/app/controllers/blame_controller.rb
index 37d7245ccb4..c950af56e26 100644
--- a/app/controllers/blame_controller.rb
+++ b/app/controllers/blame_controller.rb
@@ -7,10 +7,8 @@ class BlameController < ProjectResourceController
before_filter :authorize_code_access!
before_filter :require_non_empty_project
- before_filter :assign_ref_vars
-
def show
- @repo = @project.repo
- @blame = Grit::Blob.blame(@repo, @commit.id, @path)
+ @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path)
+ @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path)
end
end
diff --git a/app/controllers/blob_controller.rb b/app/controllers/blob_controller.rb
index d4a45d9508e..3547dfe2323 100644
--- a/app/controllers/blob_controller.rb
+++ b/app/controllers/blob_controller.rb
@@ -7,18 +7,7 @@ class BlobController < ProjectResourceController
before_filter :authorize_code_access!
before_filter :require_non_empty_project
- before_filter :assign_ref_vars
-
def show
- if @tree.is_blob?
- send_data(
- @tree.data,
- type: @tree.mime_type,
- disposition: 'inline',
- filename: @tree.name
- )
- else
- not_found!
- end
+ @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path)
end
end
diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb
index 9dc0d96883e..cde1f459d76 100644
--- a/app/controllers/commits_controller.rb
+++ b/app/controllers/commits_controller.rb
@@ -13,7 +13,6 @@ class CommitsController < ProjectResourceController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset)
- @commits = CommitDecorator.decorate_collection(@commits)
respond_to do |format|
format.html # index.html.erb
diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb
index bd3f1115173..750e9c2380e 100644
--- a/app/controllers/compare_controller.rb
+++ b/app/controllers/compare_controller.rb
@@ -8,15 +8,13 @@ class CompareController < ProjectResourceController
end
def show
- result = Commit.compare(project, params[:from], params[:to])
+ compare = Gitlab::Git::Compare.new(project.repository, params[:from], params[:to])
- @commits = result[:commits]
- @commit = result[:commit]
- @diffs = result[:diffs]
- @refs_are_same = result[:same]
+ @commits = compare.commits
+ @commit = compare.commit
+ @diffs = compare.diffs
+ @refs_are_same = compare.same
@line_notes = []
-
- @commits = CommitDecorator.decorate_collection(@commits)
end
def create
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 91a67985710..b74c22b1547 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -34,8 +34,11 @@ class DashboardController < ApplicationController
@projects
end
+ @projects = @projects.tagged_with(params[:label]) if params[:label].present?
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.page(params[:page]).per(30)
+
+ @labels = Project.where(id: @projects.map(&:id)).tags_on(:labels)
end
# Get authored or assigned open merge requests
@@ -65,7 +68,7 @@ class DashboardController < ApplicationController
end
def event_filter
- filters = cookies['event_filter'].split(',') if cookies['event_filter']
+ filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
@event_filter ||= EventFilter.new(filters)
end
end
diff --git a/app/controllers/deploy_keys_controller.rb b/app/controllers/deploy_keys_controller.rb
index a89ebbcb8d5..1c7e4c1b37a 100644
--- a/app/controllers/deploy_keys_controller.rb
+++ b/app/controllers/deploy_keys_controller.rb
@@ -5,7 +5,8 @@ class DeployKeysController < ProjectResourceController
before_filter :authorize_admin_project!
def index
- @keys = @project.deploy_keys.all
+ @enabled_keys = @project.deploy_keys.all
+ @available_keys = available_keys - @enabled_keys
end
def show
@@ -19,8 +20,9 @@ class DeployKeysController < ProjectResourceController
end
def create
- @key = @project.deploy_keys.new(params[:key])
- if @key.save
+ @key = DeployKey.new(params[:deploy_key])
+
+ if @key.valid? && @project.deploy_keys << @key
redirect_to project_deploy_keys_path(@project)
else
render "new"
@@ -36,4 +38,22 @@ class DeployKeysController < ProjectResourceController
format.js { render nothing: true }
end
end
+
+ def enable
+ project.deploy_keys << available_keys.find(params[:id])
+
+ redirect_to project_deploy_keys_path(@project)
+ end
+
+ def disable
+ @project.deploy_keys_projects.where(deploy_key_id: params[:id]).last.destroy
+
+ redirect_to project_deploy_keys_path(@project)
+ end
+
+ protected
+
+ def available_keys
+ @available_keys ||= current_user.owned_deploy_keys
+ end
end
diff --git a/app/controllers/edit_tree_controller.rb b/app/controllers/edit_tree_controller.rb
new file mode 100644
index 00000000000..9ed7a2143e4
--- /dev/null
+++ b/app/controllers/edit_tree_controller.rb
@@ -0,0 +1,49 @@
+# Controller for edit a repository's file
+class EditTreeController < ProjectResourceController
+ include ExtractsPath
+
+ # Authorize
+ before_filter :authorize_read_project!
+ before_filter :authorize_code_access!
+ before_filter :require_non_empty_project
+
+ before_filter :edit_requirements, only: [:show, :update]
+
+ def show
+ @last_commit = @project.repository.last_commit_for(@ref, @path).sha
+ end
+
+ def update
+ edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
+ updated_successfully = edit_file_action.commit!(
+ params[:content],
+ params[:commit_message],
+ params[:last_commit]
+ )
+
+ if updated_successfully
+ redirect_to project_blob_path(@project, @id), notice: "Your changes have been successfully commited"
+ else
+ flash[:notice] = "Your changes could not be commited, because the file has been changed"
+ render :show
+ end
+ end
+
+ private
+
+ def edit_requirements
+ @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path)
+
+ unless @blob.exists? && @blob.text?
+ redirect_to project_blob_path(@project, @id), notice: "You can only edit text files"
+ end
+
+ allowed = if project.protected_branch? @ref
+ can?(current_user, :push_code_to_protected_branches, project)
+ else
+ can?(current_user, :push_code, project)
+ end
+
+ return access_denied! unless allowed
+ end
+end
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
index 3cd2e77322c..bf30de565ed 100644
--- a/app/controllers/files_controller.rb
+++ b/app/controllers/files_controller.rb
@@ -1,12 +1,16 @@
class FilesController < ApplicationController
def download
note = Note.find(params[:id])
+ uploader = note.attachment
- if can?(current_user, :read_project, note.project)
- uploader = note.attachment
- send_file uploader.file.path, disposition: 'attachment'
+ if uploader.file_storage?
+ if can?(current_user, :read_project, note.project)
+ send_file uploader.file.path, disposition: 'attachment'
+ else
+ not_found!
+ end
else
- not_found!
+ redirect_to uploader.url
end
end
end
diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb
index b4bf9565112..c79ed5ca3cc 100644
--- a/app/controllers/graph_controller.rb
+++ b/app/controllers/graph_controller.rb
@@ -8,21 +8,15 @@ class GraphController < ProjectResourceController
before_filter :require_non_empty_project
def show
- if params.has_key?(:q)
- if params[:q].blank?
- redirect_to project_graph_path(@project, params[:id])
- return
- end
-
- @q = params[:q]
- @commit = @project.repository.commit(@q) || @commit
+ if @options[:q]
+ @commit = @project.repository.commit(@options[:q]) || @commit
end
respond_to do |format|
format.html
format.json do
- @graph = Network::Graph.new(project, @ref, @commit)
+ @graph = Network::Graph.new(project, @ref, @commit, @options[:filter_ref])
end
end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index bdf3567fef2..8976262f4f7 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -73,7 +73,7 @@ class GroupsController < ApplicationController
def team_members
@group.add_users_to_project_teams(params[:user_ids], params[:project_access])
- redirect_to people_group_path(@group), notice: 'Users was successfully added.'
+ redirect_to people_group_path(@group), notice: 'Users were successfully added.'
end
def edit
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 9917d198cbf..ba92ba2bdae 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -14,9 +14,18 @@ class IssuesController < ProjectResourceController
respond_to :js, :html
def index
+ terms = params['issue_search']
+
@issues = issues_filtered
+ @issues = @issues.where("title LIKE ?", "%#{terms}%") if terms.present?
@issues = @issues.page(params[:page]).per(20)
+
+ assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
+
+ @assignee = @project.users.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?
+
respond_to do |format|
format.html # index.html.erb
format.js
@@ -76,30 +85,8 @@ class IssuesController < ProjectResourceController
end
end
- def sort
- return render_404 unless can?(current_user, :admin_issue, @project)
-
- @issues = @project.issues.where(id: params['issue'])
- @issues.each do |issue|
- issue.position = params['issue'].index(issue.id.to_s) + 1
- issue.save
- end
-
- render nothing: true
- end
-
- def search
- terms = params['terms']
-
- @issues = issues_filtered
- @issues = @issues.where("title LIKE ?", "%#{terms}%") unless terms.blank?
- @issues = @issues.page(params[:page]).per(100)
-
- render partial: 'issues'
- end
-
def bulk_update
- result = IssuesBulkUpdateContext.new(project, current_user, params).execute
+ result = Issues::BulkUpdateContext.new(project, current_user, params).execute
redirect_to :back, notice: "#{result[:count]} issues updated"
end
@@ -122,6 +109,6 @@ class IssuesController < ProjectResourceController
end
def issues_filtered
- @issues = IssuesListContext.new(project, current_user, params).execute
+ @issues = Issues::ListContext.new(project, current_user, params).execute
end
end
diff --git a/app/controllers/labels_controller.rb b/app/controllers/labels_controller.rb
index 999351e22df..0e78cecf4d1 100644
--- a/app/controllers/labels_controller.rb
+++ b/app/controllers/labels_controller.rb
@@ -7,7 +7,13 @@ class LabelsController < ProjectResourceController
respond_to :js, :html
def index
- @labels = @project.issues_labels.order('count DESC')
+ @labels = @project.issues_labels
+ end
+
+ def generate
+ Gitlab::IssuesLabels.generate(@project)
+
+ redirect_to project_labels_path(@project)
end
protected
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index 88e0df16409..17c0392c384 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -20,9 +20,6 @@ class MergeRequestsController < ProjectResourceController
end
def show
- @target_type = :merge_request
- @target_id = @merge_request.id
-
respond_to do |format|
format.html
format.js
@@ -94,12 +91,10 @@ class MergeRequestsController < ProjectResourceController
def branch_from
@commit = @repository.commit(params[:ref])
- @commit = CommitDecorator.decorate(@commit)
end
def branch_to
@commit = @repository.commit(params[:ref])
- @commit = CommitDecorator.decorate(@commit)
end
def ci_status
@@ -129,11 +124,11 @@ class MergeRequestsController < ProjectResourceController
def validates_merge_request
# Show git not found page if target branch doesn't exist
- return invalid_mr unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch)
+ return invalid_mr unless @project.repository.branch_names.include?(@merge_request.target_branch)
# Show git not found page if source branch doesn't exist
# and there is no saved commits between source & target branch
- return invalid_mr if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank?
+ return invalid_mr if !@project.repository.branch_names.include?(@merge_request.source_branch) && @merge_request.commits.blank?
end
def define_show_vars
@@ -143,10 +138,12 @@ class MergeRequestsController < ProjectResourceController
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
- @commits = CommitDecorator.decorate_collection(@commits)
@allowed_to_merge = allowed_to_merge?
@show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
+
+ @target_type = :merge_request
+ @target_id = @merge_request.id
end
def allowed_to_merge?
diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb
index cdac28c1bde..25647f97576 100644
--- a/app/controllers/milestones_controller.rb
+++ b/app/controllers/milestones_controller.rb
@@ -14,7 +14,7 @@ class MilestonesController < ProjectResourceController
@milestones = case params[:f]
when 'all'; @project.milestones.order("state, due_date DESC")
when 'closed'; @project.milestones.closed.order("due_date DESC")
- else @project.milestones.active.order("due_date ASC")
+ else @project.milestones.active.order("due_date DESC")
end
@milestones = @milestones.includes(:project)
@@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController
def show
@issues = @milestone.issues
- @users = UserDecorator.decorate_collection(@milestone.participants)
+ @users = @milestone.participants.uniq
@merge_requests = @milestone.merge_requests
respond_to do |format|
diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb
index 000c7bbb641..15ca963f281 100644
--- a/app/controllers/notes_controller.rb
+++ b/app/controllers/notes_controller.rb
@@ -71,7 +71,6 @@ class NotesController < ProjectResourceController
# Helps to distinguish e.g. commit notes in mr notes list
def note_for_main_target?(note)
- note.for_wall? ||
- (@target_type.camelize == note.noteable_type && !note.for_diff_line?)
+ (@target_type.camelize == note.noteable_type && !note.for_diff_line?)
end
end
diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb
new file mode 100644
index 00000000000..4aa3172912f
--- /dev/null
+++ b/app/controllers/notifications_controller.rb
@@ -0,0 +1,21 @@
+class NotificationsController < ApplicationController
+ layout 'profile'
+
+ def show
+ @notification = current_user.notification
+ @users_projects = current_user.users_projects
+ end
+
+ def update
+ type = params[:notification_type]
+
+ @saved = if type == 'global'
+ current_user.notification_level = params[:notification_level]
+ current_user.save
+ else
+ users_project = current_user.users_projects.find(params[:notification_id])
+ users_project.notification_level = params[:notification_level]
+ users_project.save
+ end
+ end
+end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 6fa114a4194..686edd8af80 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -2,6 +2,9 @@ class ProfilesController < ApplicationController
include ActionView::Helpers::SanitizeHelper
before_filter :user
+ before_filter :authorize_change_password!, only: :update_password
+ before_filter :authorize_change_username!, only: :update_username
+
layout 'profile'
def show
@@ -53,9 +56,7 @@ class ProfilesController < ApplicationController
end
def update_username
- if @user.can_change_username?
- @user.update_attributes(username: params[:user][:username])
- end
+ @user.update_attributes(username: params[:user][:username])
respond_to do |format|
format.js
@@ -75,9 +76,17 @@ class ProfilesController < ApplicationController
# validation for this fields
%w(name skype linkedin twitter bio).each do |attr|
value = user_attributes[attr]
- user_attributes[attr] = sanitize(value) if value.present?
+ user_attributes[attr] = sanitize(strip_tags(value)) if value.present?
end
user_attributes
end
+
+ def authorize_change_password!
+ return render_404 if @user.ldap_user?
+ end
+
+ def authorize_change_username!
+ return render_404 unless @user.can_change_username?
+ end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index f2718344a3d..e202ed3234e 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -4,7 +4,7 @@ class ProjectsController < ProjectResourceController
# Authorize
before_filter :authorize_read_project!, except: [:index, :new, :create]
- before_filter :authorize_admin_project!, only: [:edit, :update, :destroy]
+ before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer]
before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
layout 'application', only: [:new, :create]
@@ -33,22 +33,22 @@ class ProjectsController < ProjectResourceController
end
def update
- status = ::Projects::UpdateContext.new(project, current_user, params).execute
+ status = ::Projects::UpdateContext.new(@project, current_user, params).execute
respond_to do |format|
if status
flash[:notice] = 'Project was successfully updated.'
- format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' }
+ format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' }
format.js
else
format.html { render action: "edit" }
format.js
end
end
+ end
- rescue Project::TransferError => ex
- @error = ex
- render :update_failed
+ def transfer
+ ::Projects::TransferContext.new(project, current_user, params).execute
end
def show
@@ -57,11 +57,11 @@ class ProjectsController < ProjectResourceController
respond_to do |format|
format.html do
- if @project.repository && !@project.repository.empty?
+ if @project.empty_repo?
+ render "projects/empty"
+ else
@last_push = current_user.recent_push(@project.id)
render :show
- else
- render "projects/empty"
end
end
format.js
@@ -78,4 +78,31 @@ class ProjectsController < ProjectResourceController
format.html { redirect_to root_path }
end
end
+
+ def fork
+ @project = ::Projects::ForkContext.new(project, current_user).execute
+
+ respond_to do |format|
+ format.html do
+ if @project.saved? && @project.forked?
+ redirect_to(@project, notice: 'Project was successfully forked.')
+ else
+ render action: "new"
+ end
+ end
+ format.js
+ end
+ end
+
+ def autocomplete_sources
+ @suggestions = {
+ emojis: Emoji.names,
+ issues: @project.issues.select([:id, :title, :description]),
+ members: @project.users.select([:username, :name]).order(:username)
+ }
+
+ respond_to do |format|
+ format.json { render :json => @suggestions }
+ end
+ end
end
diff --git a/app/controllers/public/projects_controller.rb b/app/controllers/public/projects_controller.rb
index b929b23e68c..6c0b397b4c3 100644
--- a/app/controllers/public/projects_controller.rb
+++ b/app/controllers/public/projects_controller.rb
@@ -7,6 +7,7 @@ class Public::ProjectsController < ApplicationController
def index
@projects = Project.public_only
+ @projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end
end
diff --git a/app/controllers/raw_controller.rb b/app/controllers/raw_controller.rb
new file mode 100644
index 00000000000..18b401fe611
--- /dev/null
+++ b/app/controllers/raw_controller.rb
@@ -0,0 +1,25 @@
+# Controller for viewing a file's raw
+class RawController < ProjectResourceController
+ include ExtractsPath
+
+ # Authorize
+ before_filter :authorize_read_project!
+ before_filter :authorize_code_access!
+ before_filter :require_non_empty_project
+
+ def show
+ @blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path)
+
+ if @blob.exists?
+ send_data(
+ @blob.data,
+ type: @blob.mime_type,
+ disposition: 'inline',
+ filename: @blob.name
+ )
+ else
+ not_found!
+ end
+ end
+end
+
diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb
index 0e4dba3dc4b..e7def3984f8 100644
--- a/app/controllers/refs_controller.rb
+++ b/app/controllers/refs_controller.rb
@@ -1,22 +1,22 @@
class RefsController < ProjectResourceController
+ include ExtractsPath
# Authorize
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
- before_filter :ref
- before_filter :define_tree_vars, only: [:blob, :logs_tree]
-
def switch
respond_to do |format|
format.html do
new_path = if params[:destination] == "tree"
- project_tree_path(@project, (@ref + "/" + params[:path]))
+ project_tree_path(@project, (@id))
+ elsif params[:destination] == "blob"
+ project_blob_path(@project, (@id))
elsif params[:destination] == "graph"
- project_graph_path(@project, @ref)
+ project_graph_path(@project, @id, @options)
else
- project_commits_path(@project, @ref)
+ project_commits_path(@project, @id)
end
redirect_to new_path
@@ -30,40 +30,14 @@ class RefsController < ProjectResourceController
end
def logs_tree
- contents = @tree.contents
+ 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 = CommitDecorator.decorate(last_commit)
{
file_name: content.name,
commit: last_commit
}
end
end
-
- protected
-
- def define_tree_vars
- params[:path] = nil if params[:path].blank?
-
- @repo = project.repository
- @commit = @repo.commit(@ref)
- @commit = CommitDecorator.decorate(@commit)
- @tree = Tree.new(@commit.tree, @ref, params[:path])
- @tree = TreeDecorator.new(@tree)
- @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
-
- if params[:path]
- @logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
- else
- @logs_path = logs_tree_project_ref_path(@project, @ref)
- end
- rescue
- return render_404
- end
-
- def ref
- @ref = params[:id] || params[:ref]
- end
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 507a5c206c6..194dfcd4122 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -16,8 +16,7 @@ class RegistrationsController < Devise::RegistrationsController
def build_resource(hash=nil)
super
- self.resource.projects_limit = Gitlab.config.gitlab.default_projects_limit
- self.resource
+ self.resource.with_defaults
end
private
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 229cb36949b..a7d393af82b 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -17,7 +17,7 @@ class RepositoriesController < ProjectResourceController
end
def stats
- @stats = Gitlab::GitStats.new(@repository.raw, @repository.root_ref)
+ @stats = Gitlab::Git::Stats.new(@repository.raw, @repository.root_ref)
@graph = @stats.graph
end
@@ -27,7 +27,9 @@ class RepositoriesController < ProjectResourceController
end
- file_path = @repository.archive_repo(params[:ref])
+ storage_path = Rails.root.join("tmp", "repositories")
+
+ file_path = @repository.archive_repo(params[:ref], storage_path)
if file_path
# Send file to user
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index bbd67df6c70..f5c3bb133ed 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -6,9 +6,11 @@ class SearchController < ApplicationController
project_ids = current_user.authorized_projects.map(&:id)
if group_id.present?
- group_project_ids = Group.find(group_id).projects.map(&:id)
+ @group = Group.find(group_id)
+ group_project_ids = @group.projects.map(&:id)
project_ids.select! { |id| group_project_ids.include?(id)}
elsif project_id.present?
+ @project = Project.find(params[:project_id])
project_ids.select! { |id| id == project_id.to_i}
end
@@ -18,5 +20,7 @@ class SearchController < ApplicationController
@merge_requests = result[:merge_requests]
@issues = result[:issues]
@wiki_pages = result[:wiki_pages]
+ @blobs = Kaminari.paginate_array(result[:blobs]).page(params[:page]).per(20)
+ @total_results = @projects.count + @merge_requests.count + @issues.count + @wiki_pages.count + @blobs.total_count
end
end
diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb
index 25a06501e07..fcfc4c84a91 100644
--- a/app/controllers/services_controller.rb
+++ b/app/controllers/services_controller.rb
@@ -1,25 +1,21 @@
class ServicesController < ProjectResourceController
# Authorize
before_filter :authorize_admin_project!
+ before_filter :service, only: [:edit, :update, :test]
respond_to :html
def index
- @gitlab_ci_service = @project.gitlab_ci_service
+ @project.build_missing_services
+ @services = @project.services.reload
end
def edit
- @service = @project.gitlab_ci_service
-
- # Create if missing
- @service = @project.create_gitlab_ci_service unless @service
end
def update
- @service = @project.gitlab_ci_service
-
if @service.update_attributes(params[:service])
- redirect_to edit_project_service_path(@project, :gitlab_ci)
+ redirect_to edit_project_service_path(@project, @service.to_param)
else
render 'edit'
end
@@ -28,9 +24,14 @@ class ServicesController < ProjectResourceController
def test
data = GitPushService.new.sample_data(project, current_user)
- @service = project.gitlab_ci_service
@service.execute(data)
redirect_to :back
end
+
+ private
+
+ def service
+ @service ||= @project.services.find { |service| service.to_param == params[:id] }
+ end
end
diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb
index ba55648adad..35aa315dac1 100644
--- a/app/controllers/team_members_controller.rb
+++ b/app/controllers/team_members_controller.rb
@@ -52,7 +52,7 @@ class TeamMembersController < ProjectResourceController
status = @project.team.import(giver)
notice = status ? "Succesfully imported" : "Import failed"
- redirect_to project_team_members_path(project), notice: notice
+ redirect_to project_team_index_path(project), notice: notice
end
protected
diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb
index f87d422f84e..8ef786d1a66 100644
--- a/app/controllers/teams/members_controller.rb
+++ b/app/controllers/teams/members_controller.rb
@@ -8,7 +8,6 @@ class Teams::MembersController < Teams::ApplicationController
def new
@users = User.potential_team_members(user_team)
- @users = UserDecorator.decorate_collection @users
end
def create
@@ -19,7 +18,7 @@ class Teams::MembersController < Teams::ApplicationController
user_team.add_members(user_ids, access, is_admin)
end
- redirect_to team_members_path(user_team), notice: 'Members was successfully added into Team of users.'
+ redirect_to team_members_path(user_team), notice: 'Members were successfully added into Team of users.'
end
def edit
diff --git a/app/controllers/tree_controller.rb b/app/controllers/tree_controller.rb
index 2151bd7cbbd..24e1329f926 100644
--- a/app/controllers/tree_controller.rb
+++ b/app/controllers/tree_controller.rb
@@ -7,53 +7,11 @@ class TreeController < ProjectResourceController
before_filter :authorize_code_access!
before_filter :require_non_empty_project
- before_filter :assign_ref_vars
- before_filter :edit_requirements, only: [:edit, :update]
-
def show
- @hex_path = Digest::SHA1.hexdigest(@path)
- @logs_path = logs_file_project_ref_path(@project, @ref, @path)
-
respond_to do |format|
format.html
# Disable cache so browser history works
format.js { no_cache_headers }
end
end
-
- def edit
- @last_commit = @project.repository.last_commit_for(@ref, @path).sha
- end
-
- def update
- edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
- updated_successfully = edit_file_action.commit!(
- params[:content],
- params[:commit_message],
- params[:last_commit]
- )
-
- if updated_successfully
- redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited"
- else
- flash[:notice] = "Your changes could not be commited, because the file has been changed"
- render :edit
- end
- end
-
- private
-
- def edit_requirements
- unless @tree.is_blob? && @tree.text?
- redirect_to project_tree_path(@project, @id), notice: "You can only edit text files"
- end
-
- allowed = if project.protected_branch? @ref
- can?(current_user, :push_code_to_protected_branches, project)
- else
- can?(current_user, :push_code, project)
- end
-
- return access_denied! unless allowed
- end
end
diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb
index 940b1e97340..be9ae4f37a4 100644
--- a/app/controllers/wikis_controller.rb
+++ b/app/controllers/wikis_controller.rb
@@ -49,9 +49,9 @@ class WikisController < ProjectResourceController
end
def history
- unless @wiki = @gollum_wiki.find_page(params[:id])
- redirect_to project_wiki_path(@project, :home), notice: "Page not found"
- end
+ @wiki = @gollum_wiki.find_page(params[:id])
+
+ redirect_to(project_wiki_path(@project, :home), notice: "Page not found") unless @wiki
end
def destroy
diff --git a/app/decorators/application_decorator.rb b/app/decorators/application_decorator.rb
deleted file mode 100644
index b805b3479b8..00000000000
--- a/app/decorators/application_decorator.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class ApplicationDecorator < Draper::Decorator
- delegate_all
- # Lazy Helpers
- # PRO: Call Rails helpers without the h. proxy
- # ex: number_to_currency(model.price)
- # CON: Add a bazillion methods into your decorator's namespace
- # and probably sacrifice performance/memory
- #
- # Enable them by uncommenting this line:
- # lazy_helpers
-
- # Shared Decorations
- # Consider defining shared methods common to all your models.
- #
- # Example: standardize the formatting of timestamps
- #
- # def formatted_timestamp(time)
- # h.content_tag :span, time.strftime("%a %m/%d/%y"),
- # class: 'timestamp'
- # end
- #
- # def created_at
- # formatted_timestamp(model.created_at)
- # end
- #
- # def updated_at
- # formatted_timestamp(model.updated_at)
- # end
-end
diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb
deleted file mode 100644
index 0337d8d43ce..00000000000
--- a/app/decorators/commit_decorator.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-class CommitDecorator < ApplicationDecorator
- decorates :commit
-
- # Returns a string describing the commit for use in a link title
- #
- # Example
- #
- # "Commit: Alex Denisov - Project git clone panel"
- def link_title
- "Commit: #{author_name} - #{title}"
- end
-
- # Returns the commits title.
- #
- # Usually, the commit title is the first line of the commit message.
- # In case this first line is longer than 80 characters, it is cut off
- # after 70 characters and ellipses (`&hellp;`) are appended.
- def title
- title = safe_message
-
- return no_commit_message if title.blank?
-
- title_end = title.index(/\n/)
- if (!title_end && title.length > 80) || (title_end && title_end > 80)
- title[0..69] << "&hellip;".html_safe
- else
- title.split(/\n/, 2).first
- end
- end
-
- # Returns the commits description
- #
- # cut off, ellipses (`&hellp;`) are prepended to the commit message.
- def description
- description = safe_message
-
- title_end = description.index(/\n/)
- if (!title_end && description.length > 80) || (title_end && title_end > 80)
- "&hellip;".html_safe << description[70..-1]
- else
- description.split(/\n/, 2)[1].try(:chomp)
- end
- end
-
- # Returns a link to the commit author. If the author has a matching user and
- # is a member of the current @project it will link to the team member page.
- # Otherwise it will link to the author email as specified in the commit.
- #
- # options:
- # avatar: true will prepend the avatar image
- # size: size of the avatar image in px
- def author_link(options = {})
- person_link(options.merge source: :author)
- end
-
- # Just like #author_link but for the committer.
- def committer_link(options = {})
- person_link(options.merge source: :committer)
- end
-
- protected
-
- def no_commit_message
- "--no commit message"
- end
-
- # Private: Returns a link to a person. If the person has a matching user and
- # is a member of the current @project it will link to the team member page.
- # Otherwise it will link to the person email as specified in the commit.
- #
- # options:
- # source: one of :author or :committer
- # avatar: true will prepend the avatar image
- # size: size of the avatar image in px
- def person_link(options = {})
- source_name = send "#{options[:source]}_name".to_sym
- source_email = send "#{options[:source]}_email".to_sym
- text = if options[:avatar]
- avatar = h.image_tag h.gravatar_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>}
- else
- source_name
- end
-
- user = User.where('name like ? or email like ?', source_name, source_email).first
-
- if user.nil?
- h.mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link")
- else
- h.link_to(text.html_safe, h.user_path(user), class: "commit-#{options[:source]}-link")
- end
- end
-end
diff --git a/app/decorators/event_decorator.rb b/app/decorators/event_decorator.rb
deleted file mode 100644
index 1b0ad0da28f..00000000000
--- a/app/decorators/event_decorator.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class EventDecorator < ApplicationDecorator
- decorates :event
-
- def feed_title
- if self.issue?
- "#{self.author_name} #{self.action_name} issue ##{self.target_id}: #{self.issue_title} at #{self.project.name}"
- elsif self.merge_request?
- "#{self.author_name} #{self.action_name} MR ##{self.target_id}: #{self.merge_request_title} at #{self.project.name}"
- elsif self.push?
- "#{self.author_name} #{self.push_action_name} #{self.ref_type} #{self.ref_name} at #{self.project.name}"
- elsif self.membership_changed?
- "#{self.author_name} #{self.action_name} #{self.project.name}"
- else
- ""
- end
- end
-
- def feed_url
- if self.issue?
- h.project_issue_url(self.project, self.issue)
- elsif self.merge_request?
- h.project_merge_request_url(self.project, self.merge_request)
-
- elsif self.push?
- if self.push_with_commits?
- if self.commits_count > 1
- h.project_compare_url(self.project, :from => self.parent_commit.id, :to => self.last_commit.id)
- else
- h.project_commit_url(self.project, :id => self.last_commit.id)
- end
- else
- h.project_commits_url(self.project, self.ref_name)
- end
- end
- end
-
- def feed_summary
- if self.issue?
- h.render "events/event_issue", issue: self.issue
- elsif self.push?
- h.render "events/event_push", event: self
- end
- end
-end
diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb
deleted file mode 100644
index 0e760f97dee..00000000000
--- a/app/decorators/tree_decorator.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class TreeDecorator < ApplicationDecorator
- decorates :tree
-
- def breadcrumbs(max_links = 2)
- if path
- part_path = ""
- parts = path.split("\/")
-
- yield('..', nil) if parts.count > max_links
-
- parts.each do |part|
- part_path = File.join(part_path, part) unless part_path.empty?
- part_path = part if part_path.empty?
-
- next unless parts.last(2).include?(part) if parts.count > max_links
- yield(part, h.tree_join(ref, part_path))
- end
- end
- end
-
- def up_dir?
- path.present?
- end
-
- def up_dir_path
- file = File.join(path, "..")
- h.tree_join(ref, file)
- end
-
- def readme
- @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }
- end
-end
diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb
deleted file mode 100644
index af9c6a63e75..00000000000
--- a/app/decorators/user_decorator.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class UserDecorator < ApplicationDecorator
- decorates :user
-
- def avatar_image size = 16
- h.image_tag h.gravatar_icon(self.email, size), class: "avatar #{"s#{size}"}", width: size
- end
-
- def tm_of(project)
- project.team_member_by_id(self.id)
- end
-end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index f03039e4b75..488a55b2e6c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -2,6 +2,13 @@ require 'digest/md5'
require 'uri'
module ApplicationHelper
+ COLOR_SCHEMES = {
+ 1 => 'white',
+ 2 => 'black',
+ 3 => 'solarized-dark',
+ 4 => 'monokai',
+ }
+ COLOR_SCHEMES.default = 'white'
# Check if a particular controller is the current one
#
@@ -37,7 +44,7 @@ module ApplicationHelper
if !Gitlab.config.gravatar.enabled || user_email.blank?
'no_avatar.png'
else
- gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
+ gravatar_url = request.ssl? || gitlab_config.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
user_email.strip!
sprintf gravatar_url, hash: Digest::MD5.hexdigest(user_email.downcase), size: size
end
@@ -96,7 +103,7 @@ module ApplicationHelper
]
project_nav = []
- if @project && @project.repository && @project.repository.root_ref
+ if @project && @project.repository.exists? && @project.repository.root_ref
project_nav = [
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
@@ -119,31 +126,29 @@ module ApplicationHelper
Emoji.names.to_s
end
- def ldap_enable?
- Devise.omniauth_providers.include?(:ldap)
- end
-
def app_theme
Gitlab::Theme.css_class_by_id(current_user.try(:theme_id))
end
def user_color_scheme_class
- case current_user.color_scheme_id
- when 1 then 'white'
- when 2 then 'black'
- when 3 then 'solarized-dark'
- else
- 'white'
- end
+ COLOR_SCHEMES[current_user.try(:color_scheme_id)]
end
+ # Define whenever show last push event
+ # with suggestion to create MR
def show_last_push_widget?(event)
- event &&
- event.last_push_to_non_root? &&
- !event.rm_ref? &&
- event.project &&
- event.project.repository &&
- event.project.merge_requests_enabled
+ # Skip if event is not about added or modified non-master branch
+ return false unless event && event.last_push_to_non_root? && !event.rm_ref?
+
+ project = event.project
+
+ # Skip if project repo is empty or MR disabled
+ return false unless project && !project.empty_repo? && project.merge_requests_enabled
+
+ # Skip if user already created appropriate MR
+ return false if project.merge_requests.where(source_branch: event.branch_name).opened.any?
+
+ true
end
def hexdigest(string)
@@ -151,9 +156,8 @@ module ApplicationHelper
end
def project_last_activity project
- activity = project.last_activity
- if activity && activity.created_at
- time_ago_in_words(activity.created_at) + " ago"
+ if project.last_activity_at
+ time_ago_in_words(project.last_activity_at) + " ago"
else
"Never"
end
@@ -181,4 +185,21 @@ module ApplicationHelper
css_class << " multiselect" if opts[:multiple]
hidden_field_tag(id, '', class: css_class)
end
+
+ def body_data_page
+ path = controller.controller_path.split('/')
+ namespace = path.first if path.second
+
+ [namespace, controller.controller_name, controller.action_name].compact.join(":")
+ end
+
+ # shortcut for gitlab config
+ def gitlab_config
+ Gitlab.config.gitlab
+ end
+
+ # shortcut for gitlab extra config
+ def extra_config
+ Gitlab.config.extra
+ end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index acdd48e04eb..95ca294cd2d 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -1,4 +1,20 @@
module CommitsHelper
+ # Returns a link to the commit author. If the author has a matching user and
+ # is a member of the current @project it will link to the team member page.
+ # Otherwise it will link to the author email as specified in the commit.
+ #
+ # options:
+ # avatar: true will prepend the avatar image
+ # size: size of the avatar image in px
+ def commit_author_link(commit, options = {})
+ commit_person_link(commit, options.merge(source: :author))
+ end
+
+ # Just like #author_link but for the committer.
+ def commit_committer_link(commit, options = {})
+ commit_person_link(commit, options.merge(source: :committer))
+ end
+
def identification_type(line)
if line[0] == "+"
"new"
@@ -93,9 +109,7 @@ module CommitsHelper
end
def commit_to_html commit
- if commit.model
- escape_javascript(render 'commits/commit', commit: commit)
- end
+ escape_javascript(render 'commits/commit', commit: commit)
end
def diff_line_content(line)
@@ -105,4 +119,58 @@ module CommitsHelper
line
end
end
+
+ # Breadcrumb links for a Project and, if applicable, a tree path
+ def commits_breadcrumbs
+ return unless @project && @ref
+
+ # Add the root project link and the arrow icon
+ crumbs = content_tag(:li) do
+ content_tag(:span, nil, class: 'arrow') +
+ link_to(@project.name, project_commits_path(@project, @ref))
+ end
+
+ if @path
+ parts = @path.split('/')
+
+ parts.each_with_index do |part, i|
+ crumbs += content_tag(:span, '/', class: 'divider')
+ crumbs += content_tag(:li) do
+ # The text is just the individual part, but the link needs all the parts before it
+ link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
+ end
+ end
+ end
+
+ crumbs.html_safe
+ end
+
+ protected
+
+ # Private: Returns a link to a person. If the person has a matching user and
+ # is a member of the current @project it will link to the team member page.
+ # Otherwise it will link to the person email as specified in the commit.
+ #
+ # options:
+ # source: one of :author or :committer
+ # avatar: true will prepend the avatar image
+ # size: size of the avatar image in px
+ def commit_person_link(commit, options = {})
+ source_name = commit.send "#{options[:source]}_name".to_sym
+ source_email = commit.send "#{options[:source]}_email".to_sym
+ text = if options[:avatar]
+ avatar = image_tag(gravatar_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>}
+ else
+ source_name
+ end
+
+ user = User.where('name like ? or email like ?', source_name, source_email).first
+
+ if user.nil?
+ mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link")
+ else
+ link_to(text.html_safe, user_path(user), class: "commit-#{options[:source]}-link")
+ end
+ end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 38374e3394d..7155036eeed 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -42,4 +42,45 @@ module EventsHelper
EventFilter.team => "icon-user",
}
end
+
+ def event_feed_title(event)
+ if event.issue?
+ "#{event.author_name} #{event.action_name} issue ##{event.target_id}: #{event.issue_title} at #{event.project.name}"
+ elsif event.merge_request?
+ "#{event.author_name} #{event.action_name} MR ##{event.target_id}: #{event.merge_request_title} at #{event.project.name}"
+ elsif event.push?
+ "#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project.name}"
+ elsif event.membership_changed?
+ "#{event.author_name} #{event.action_name} #{event.project.name}"
+ else
+ ""
+ end
+ end
+
+ def event_feed_url(event)
+ if event.issue?
+ project_issue_url(event.project, event.issue)
+ elsif event.merge_request?
+ project_merge_request_url(event.project, event.merge_request)
+
+ elsif event.push?
+ if event.push_with_commits?
+ if event.commits_count > 1
+ project_compare_url(event.project, from: event.commit_from, to: event.commit_to)
+ else
+ project_commit_url(event.project, id: event.commit_to)
+ end
+ else
+ project_commits_url(event.project, event.ref_name)
+ end
+ end
+ end
+
+ def event_feed_summary(event)
+ if event.issue?
+ render "events/event_issue", issue: event.issue
+ elsif event.push?
+ render "events/event_push", event: event
+ end
+ end
end
diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb
index 369330151f4..71a07d6cad1 100644
--- a/app/helpers/graph_helper.rb
+++ b/app/helpers/graph_helper.rb
@@ -1,6 +1,12 @@
module GraphHelper
- def join_with_space(ary)
- ary.collect{|r|r.name}.join(" ") unless ary.nil?
+ def get_refs(commit)
+ refs = ""
+ refs += commit.refs.collect{|r|r.name}.join(" ") if commit.refs
+
+ # append note count
+ refs += "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0
+
+ refs
end
def parents_zip_spaces(parents, parent_spaces)
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 54385117c26..dc5aa6e1fb6 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -11,10 +11,6 @@ module IssuesHelper
classes
end
- def issue_tags
- @project.issues.tag_counts_on(:labels).map(&:name)
- end
-
# Returns an OpenStruct object suitable for use by <tt>options_from_collection_for_select</tt>
# to allow filtering issues by an unassigned User or Milestone
def unassigned_filter
@@ -32,12 +28,6 @@ module IssuesHelper
}
end
- def labels_autocomplete_source
- labels = @project.issues_labels.order('count DESC')
- labels = labels.map{ |l| { label: l.name, value: l.name } }
- labels.to_json
- end
-
def issues_active_milestones
@project.milestones.active.order("id desc").all
end
@@ -48,19 +38,31 @@ module IssuesHelper
if @project.used_default_issues_tracker?
project_issues_filter_path(@project)
else
- url = Settings[:issues_tracker][@project.issues_tracker]["project_url"]
+ url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"]
url.gsub(':project_id', @project.id.to_s)
.gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
end
end
+ def url_for_new_issue
+ return "" if @project.nil?
+
+ if @project.used_default_issues_tracker?
+ url = new_project_issue_path project_id: @project
+ else
+ url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"]
+ url.gsub(':project_id', @project.id.to_s)
+ .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
+ end
+ end
+
def url_for_issue(issue_id)
return "" if @project.nil?
if @project.used_default_issues_tracker?
url = project_issue_url project_id: @project, id: issue_id
else
- url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"]
+ url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"]
url.gsub(':id', issue_id.to_s)
.gsub(':project_id', @project.id.to_s)
.gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
@@ -76,4 +78,15 @@ module IssuesHelper
""
end
end
+
+ def project_issues_with_filter_path(project, opts)
+ default_opts = {
+ status: params[:status],
+ label_name: params[:label_name],
+ milestone_id: params[:milestone_id],
+ assignee_id: params[:assignee_id],
+ }
+
+ project_issues_path(@project, default_opts.merge(opts))
+ end
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
new file mode 100644
index 00000000000..9a6aea85ee9
--- /dev/null
+++ b/app/helpers/labels_helper.rb
@@ -0,0 +1,28 @@
+module LabelsHelper
+ def issue_label_names
+ @project.issues_labels.map(&:name)
+ end
+
+ def labels_autocomplete_source
+ labels = @project.issues_labels
+ labels = labels.map{ |l| { label: l.name, value: l.name } }
+ labels.to_json
+ end
+
+ def label_css_class(name)
+ klass = Gitlab::IssuesLabels
+
+ case name
+ when *klass.warning_labels
+ 'label-warning'
+ when *klass.neutral_labels
+ 'label-inverse'
+ when *klass.positive_labels
+ 'label-success'
+ when *klass.important_labels
+ 'label-important'
+ else
+ 'label-info'
+ end
+ end
+end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 155d03d1147..05ffec066f8 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -11,7 +11,7 @@ module MergeRequestsHelper
end
def mr_css_classes mr
- classes = "merge_request"
+ classes = "merge-request"
classes << " closed" if mr.closed?
classes << " merged" if mr.merged?
classes
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
new file mode 100644
index 00000000000..7342393a707
--- /dev/null
+++ b/app/helpers/notifications_helper.rb
@@ -0,0 +1,2 @@
+module NotificationsHelper
+end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
new file mode 100644
index 00000000000..c0177dacbf8
--- /dev/null
+++ b/app/helpers/oauth_helper.rb
@@ -0,0 +1,19 @@
+module OauthHelper
+ def ldap_enabled?
+ Devise.omniauth_providers.include?(:ldap)
+ end
+
+ def default_providers
+ [:twitter, :github, :google_oauth2, :ldap]
+ end
+
+ def enabled_oauth_providers
+ Devise.omniauth_providers
+ end
+
+ def enabled_social_providers
+ enabled_oauth_providers.select do |name|
+ [:twitter, :github, :google_oauth2].include?(name.to_sym)
+ end
+ end
+end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index e6427ea84c0..9b142714980 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -25,7 +25,7 @@ module ProjectsHelper
author_html = ""
# Build avatar image tag
- author_html << image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") if opts[:avatar]
+ author_html << image_tag(gravatar_icon(author.try(:email)), width: 16, class: "avatar avatar-inline s16") if opts[:avatar]
# Build name span tag
author_html << content_tag(:span, sanitize(author.name), class: 'author')
@@ -44,4 +44,8 @@ module ProjectsHelper
project.name
end
end
+
+ def remove_project_message(project)
+ "You are going to remove #{project.name_with_namespace}.\n Removed project CANNOT be restored!\n Are you ABSOLUTELY sure?"
+ end
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index fab0085ba73..a8491dfe3ba 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -3,26 +3,20 @@ module TreeHelper
# their corresponding partials
#
# contents - A Grit::Tree object for the current tree
- def render_tree(contents)
+ def render_tree(tree)
# Render Folders before Files/Submodules
- folders, files = contents.partition { |v| v.kind_of?(Grit::Tree) }
+ folders, files, submodules = tree.trees, tree.blobs, tree.submodules
tree = ""
# Render folders if we have any
tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
- files.each do |f|
- html = if f.respond_to?(:url)
- # Object is a Submodule
- render partial: 'tree/submodule_item', object: f
- else
- # Object is a Blob
- render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
- end
+ # Render files if we have any
+ tree += render partial: 'tree/blob_item', collection: files, locals: {type: 'file'} if files.present?
- tree += html if html.present?
- end
+ # Render submodules if we have any
+ tree += render partial: 'tree/submodule_item', collection: submodules if submodules.present?
tree.html_safe
end
@@ -70,28 +64,29 @@ module TreeHelper
end
end
- # Breadcrumb links for a Project and, if applicable, a tree path
- def breadcrumbs
- return unless @project && @ref
+ def tree_breadcrumbs(tree, max_links = 2)
+ if tree.path
+ part_path = ""
+ parts = tree.path.split("\/")
- # Add the root project link and the arrow icon
- crumbs = content_tag(:li) do
- content_tag(:span, nil, class: 'arrow') +
- link_to(@project.name, project_commits_path(@project, @ref))
- end
+ yield('..', nil) if parts.count > max_links
- if @path
- parts = @path.split('/')
+ parts.each do |part|
+ part_path = File.join(part_path, part) unless part_path.empty?
+ part_path = part if part_path.empty?
- parts.each_with_index do |part, i|
- crumbs += content_tag(:span, '/', class: 'divider')
- crumbs += content_tag(:li) do
- # The text is just the individual part, but the link needs all the parts before it
- link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
- end
+ next unless parts.last(2).include?(part) if parts.count > max_links
+ yield(part, tree_join(tree.ref, part_path))
end
end
+ end
+
+ def up_dir_path tree
+ file = File.join(tree.path, "..")
+ tree_join(tree.ref, file)
+ end
- crumbs.html_safe
+ def leave_edit_message
+ "Leave edit mode?\nAll unsaved changes will be lost."
end
end
diff --git a/app/helpers/user_teams_helper.rb b/app/helpers/user_teams_helper.rb
index 2055bb3c8bc..8603ee434a8 100644
--- a/app/helpers/user_teams_helper.rb
+++ b/app/helpers/user_teams_helper.rb
@@ -22,5 +22,4 @@ module UserTeamsHelper
def remove_from_user_team_message(team, member)
"You are going to remove #{member.name} from #{team.name}. Are you sure?"
end
-
end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index 5b69886f9ce..79731b60f45 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -1,9 +1,9 @@
module Emails
module Issues
- def new_issue_email(issue_id)
+ def new_issue_email(recipient_id, issue_id)
@issue = Issue.find(issue_id)
@project = @issue.project
- mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
+ mail(to: recipient(recipient_id), subject: subject("new issue ##{@issue.id}", @issue.title))
end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
@@ -13,6 +13,14 @@ module Emails
mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
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.id}", @issue.title))
+ end
+
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
@issue = Issue.find issue_id
@issue_status = status
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index 35890460e05..806f1b01b72 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -1,9 +1,9 @@
module Emails
module MergeRequests
- def new_merge_request_email(merge_request_id)
+ def new_merge_request_email(recipient_id, merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
- mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
+ mail(to: recipient(recipient_id), subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
@@ -12,5 +12,18 @@ module Emails
@project = @merge_request.project
mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
end
+
+ def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
+ @merge_request = MergeRequest.find(merge_request_id)
+ @project = @merge_request.project
+ @updated_by = User.find updated_by_user_id
+ mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.id}", @merge_request.title))
+ 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.id}", @merge_request.title))
+ end
end
end
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index de51debfeb5..769b6e0b861 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -3,7 +3,6 @@ module Emails
def note_commit_email(recipient_id, note_id)
@note = Note.find(note_id)
@commit = @note.noteable
- @commit = CommitDecorator.decorate(@commit)
@project = @note.project
mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index b86a4b5a044..24b6ad182b4 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -38,11 +38,11 @@ class Ability
elsif team.reporters.include?(user)
rules << project_report_rules
- elsif team.guests.include?(user)
+ elsif team.guests.include?(user) or project.public?
rules << project_guest_rules
end
- if project.owner == user
+ if project.owner == user || user.admin?
rules << project_admin_rules
end
@@ -68,6 +68,7 @@ class Ability
def project_report_rules
project_guest_rules + [
:download_code,
+ :fork_project
:write_project_snippet
]
end
diff --git a/app/models/campfire_service.rb b/app/models/campfire_service.rb
new file mode 100644
index 00000000000..6450ffe7318
--- /dev/null
+++ b/app/models/campfire_service.rb
@@ -0,0 +1,76 @@
+# == 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)
+#
+
+class CampfireService < Service
+ attr_accessible :subdomain, :room
+
+ validates :token, presence: true, if: :activated?
+
+ def title
+ 'Campfire'
+ end
+
+ def description
+ 'Simple web-based real-time group chat'
+ end
+
+ def to_param
+ 'campfire'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'token', placeholder: '' },
+ { type: 'text', name: 'subdomain', placeholder: '' },
+ { type: 'text', name: 'room', placeholder: '' }
+ ]
+ end
+
+ def execute(push_data)
+ room = gate.find_room_by_name(self.room)
+ return true unless room
+
+ message = build_message(push_data)
+
+ room.speak(message)
+ end
+
+ private
+
+ def gate
+ @gate ||= Tinder::Campfire.new(subdomain, token: token)
+ end
+
+ def build_message(push)
+ ref = push[:ref].gsub("refs/heads/", "")
+ before = push[:before]
+ after = push[:after]
+
+ message = ""
+ message << "[#{project.name_with_namespace}] "
+ message << "#{push[:user_name]} "
+
+ if before =~ /000000/
+ message << "pushed new branch #{ref} \n"
+ elsif after =~ /000000/
+ message << "removed branch #{ref} \n"
+ else
+ message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
+ message << "#{project.web_url}/compare/#{before}...#{after}"
+ end
+
+ message
+ end
+end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 4d0c57b35fd..e3363350997 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -8,174 +8,70 @@ class Commit
#
DIFF_SAFE_SIZE = 100
- attr_accessor :commit, :head, :refs
-
- delegate :message, :authored_date, :committed_date, :parents, :sha,
- :date, :committer, :author, :diffs, :tree, :id, :stats,
- :to_patch, to: :commit
-
- class << self
- def find_or_first(repo, commit_id = nil, root_ref)
- commit = if commit_id
- repo.commit(commit_id)
- else
- repo.commits(root_ref).first
- end
-
- Commit.new(commit) if commit
- end
-
- def fresh_commits(repo, n = 10)
- commits = repo.heads.map do |h|
- repo.commits(h.name, n).map { |c| Commit.new(c, h) }
- end.flatten.uniq { |c| c.id }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits[0...n]
- end
-
- def commits_with_refs(repo, n = 20)
- commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits[0..n]
- end
-
- def commits_since(repo, date)
- commits = repo.heads.map do |h|
- repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
- end.flatten.uniq { |c| c.id }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits
- end
-
- def commits(repo, ref, path = nil, limit = nil, offset = nil)
- if path
- repo.log(ref, path, max_count: limit, skip: offset)
- elsif limit && offset
- repo.commits(ref, limit, offset)
- else
- repo.commits(ref)
- end.map{ |c| Commit.new(c) }
- end
-
- def commits_between(repo, from, to)
- repo.commits_between(from, to).map { |c| Commit.new(c) }
- end
-
- def compare(project, from, to)
- result = {
- commits: [],
- diffs: [],
- commit: nil,
- same: false
- }
-
- return result unless from && to
-
- first = project.repository.commit(to.try(:strip))
- last = project.repository.commit(from.try(:strip))
-
- if first && last
- result[:same] = (first.id == last.id)
- result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)}
-
- # Dont load diff for 100+ commits
- result[:diffs] = if result[:commits].size > 100
- []
- else
- project.repo.diff(last.id, first.id) rescue []
- end
-
- result[:commit] = Commit.new(first)
- end
-
- result
- end
- end
-
- def initialize(raw_commit, head = nil)
- raise "Nil as raw commit passed" unless raw_commit
-
- @commit = raw_commit
- @head = head
- end
-
- def short_id(length = 10)
- id.to_s[0..length]
+ def self.decorate(commits)
+ commits.map { |c| self.new(c) }
end
- def safe_message
- @safe_message ||= message
- end
-
- def created_at
- committed_date
- end
+ attr_accessor :raw
- def author_email
- author.email
- end
+ def initialize(raw_commit)
+ raise "Nil as raw commit passed" unless raw_commit
- def author_name
- author.name
+ @raw = raw_commit
end
- # Was this commit committed by a different person than the original author?
- def different_committer?
- author_name != committer_name || author_email != committer_email
+ def id
+ @raw.id
end
- def committer_name
- committer.name
+ # Returns a string describing the commit for use in a link title
+ #
+ # Example
+ #
+ # "Commit: Alex Denisov - Project git clone panel"
+ def link_title
+ "Commit: #{author_name} - #{title}"
end
- def committer_email
- committer.email
+ # Returns the commits title.
+ #
+ # Usually, the commit title is the first line of the commit message.
+ # In case this first line is longer than 80 characters, it is cut off
+ # after 70 characters and ellipses (`&hellp;`) are appended.
+ def title
+ title = safe_message
+
+ return no_commit_message if title.blank?
+
+ title_end = title.index(/\n/)
+ if (!title_end && title.length > 80) || (title_end && title_end > 80)
+ title[0..69] << "&hellip;".html_safe
+ else
+ title.split(/\n/, 2).first
+ end
end
- def prev_commit
- @prev_commit ||= if parents.present?
- Commit.new(parents.first)
- else
- nil
- end
+ # Returns the commits description
+ #
+ # cut off, ellipses (`&hellp;`) are prepended to the commit message.
+ def description
+ description = safe_message
+
+ title_end = description.index(/\n/)
+ if (!title_end && description.length > 80) || (title_end && title_end > 80)
+ "&hellip;".html_safe << description[70..-1]
+ else
+ description.split(/\n/, 2)[1].try(:chomp)
+ end
end
- def prev_commit_id
- prev_commit.try :id
+ def method_missing(m, *args, &block)
+ @raw.send(m, *args, &block)
end
- # Shows the diff between the commit's parent and the commit.
- #
- # Cuts out the header and stats from #to_patch and returns only the diff.
- def to_diff
- # see Grit::Commit#show
- patch = to_patch
-
- # discard lines before the diff
- lines = patch.split("\n")
- while !lines.first.start_with?("diff --git") do
- lines.shift
- end
- lines.pop if lines.last =~ /^[\d.]+$/ # Git version
- lines.pop if lines.last == "-- " # end of diff
- lines.join("\n")
- end
+ def respond_to?(method)
+ return true if @raw.respond_to?(method)
- def has_zero_stats?
- stats.total.zero?
- rescue
- true
+ super
end
end
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
new file mode 100644
index 00000000000..548ef4f9a27
--- /dev/null
+++ b/app/models/deploy_key.rb
@@ -0,0 +1,6 @@
+class DeployKey < Key
+ has_many :deploy_keys_projects, dependent: :destroy
+ has_many :projects, through: :deploy_keys_projects
+
+ scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
+end
diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb
new file mode 100644
index 00000000000..48350a3e4d9
--- /dev/null
+++ b/app/models/deploy_keys_project.rb
@@ -0,0 +1,11 @@
+class DeployKeysProject < ActiveRecord::Base
+ attr_accessible :key_id, :project_id
+
+ belongs_to :project
+ belongs_to :deploy_key
+
+ validates :deploy_key_id, presence: true
+ validates :deploy_key_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
+
+ validates :project_id, presence: true
+end
diff --git a/app/models/event.rb b/app/models/event.rb
index d39445c4ffe..4b75087dc2a 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -134,7 +134,7 @@ class Event < ActiveRecord::Base
if closed?
"closed"
elsif merged?
- "merged"
+ "accepted"
elsif joined?
'joined'
elsif left?
@@ -200,7 +200,7 @@ class Event < ActiveRecord::Base
# Max 20 commits from push DESC
def commits
- @commits ||= data[:commits].map { |commit| repository.commit(commit[:id]) }.reverse
+ @commits ||= data[:commits].reverse
end
def commits_count
@@ -221,26 +221,8 @@ class Event < ActiveRecord::Base
end
end
- def repository
- project.repository
- end
-
- def parent_commit
- repository.commit(commit_from)
- rescue => ex
- nil
- end
-
- def last_commit
- repository.commit(commit_to)
- rescue => ex
- nil
- end
-
def push_with_commits?
- md_ref? && commits.any? && parent_commit && last_commit
- rescue Grit::NoSuchPathError
- false
+ md_ref? && commits.any? && commit_from && commit_to
end
def last_push_to_non_root?
diff --git a/app/models/forked_project_link.rb b/app/models/forked_project_link.rb
new file mode 100644
index 00000000000..c3199ca264e
--- /dev/null
+++ b/app/models/forked_project_link.rb
@@ -0,0 +1,8 @@
+class ForkedProjectLink < ActiveRecord::Base
+ attr_accessible :forked_from_project_id, :forked_to_project_id
+
+ # Relations
+ belongs_to :forked_to_project, class_name: Project
+ belongs_to :forked_from_project, class_name: Project
+
+end
diff --git a/app/models/gitlab_ci_service.rb b/app/models/gitlab_ci_service.rb
index 4eb39c7ef4d..bdbe7724be0 100644
--- a/app/models/gitlab_ci_service.rb
+++ b/app/models/gitlab_ci_service.rb
@@ -46,4 +46,31 @@ class GitlabCiService < Service
def build_page sha
project_url + "/builds/#{sha}"
end
+
+ def builds_path
+ project_url + "?ref=" + project.default_branch
+ end
+
+ def status_img_path
+ project_url + "/status.png?ref=" + project.default_branch
+ end
+
+ def title
+ 'GitLab CI'
+ end
+
+ def description
+ 'Continuous integration server from GitLab'
+ end
+
+ def to_param
+ 'gitlab_ci'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
+ { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3'}
+ ]
+ end
end
diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb
index a1ee3a0899a..d1edbab4533 100644
--- a/app/models/gollum_wiki.rb
+++ b/app/models/gollum_wiki.rb
@@ -16,6 +16,10 @@ class GollumWiki
@user = user
end
+ def path
+ @project.path + '.wiki'
+ end
+
def path_with_namespace
@project.path_with_namespace + ".wiki"
end
@@ -47,12 +51,6 @@ class GollumWiki
wiki.pages.map { |page| WikiPage.new(self, page, true) }
end
- # Returns the last 30 Commit objects across the entire
- # repository.
- def recent_history
- Commit.fresh_commits(wiki.repo, 30)
- end
-
# Finds a page within the repository based on a tile
# or slug.
#
@@ -90,13 +88,17 @@ class GollumWiki
private
def create_repo!
- if gitlab_shell.add_repository(path_with_namespace)
+ if init_repo(path_with_namespace)
Gollum::Wiki.new(path_to_repo)
else
raise CouldNotCreateWikiError
end
end
+ def init_repo(path_with_namespace)
+ gitlab_shell.add_repository(path_with_namespace)
+ end
+
def commit_details(action, message = nil, title = nil)
commit_message = message || default_message(action, title)
@@ -114,5 +116,4 @@ class GollumWiki
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end
-
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 5d838d2b9b0..17671c3defe 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -13,6 +13,7 @@
#
class Group < Namespace
+
def add_users_to_project_teams(user_ids, project_access)
UsersProject.add_users_into_projects(
projects.map(&:id),
diff --git a/app/models/hipchat_service.rb b/app/models/hipchat_service.rb
new file mode 100644
index 00000000000..13429fa83b4
--- /dev/null
+++ b/app/models/hipchat_service.rb
@@ -0,0 +1,73 @@
+# == 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)
+#
+
+class HipchatService < Service
+ attr_accessible :room
+
+ validates :token, presence: true, if: :activated?
+
+ def title
+ 'Hipchat'
+ end
+
+ def description
+ 'Simple web-based real-time group chat'
+ end
+
+ def to_param
+ 'hipchat'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'token', placeholder: '' },
+ { type: 'text', name: 'room', placeholder: '' }
+ ]
+ end
+
+ def execute(push_data)
+ gate[room].send('Gitlab', create_message(push_data))
+ end
+
+ private
+
+ def gate
+ @gate ||= HipChat::Client.new(token)
+ end
+
+ def create_message(push)
+ ref = push[:ref].gsub("refs/heads/", "")
+ before = push[:before]
+ after = push[:after]
+
+ message = ""
+ message << "#{push[:user_name]} "
+ if before =~ /000000/
+ message << "pushed new branch <a href=\"#{project.web_url}/commits/#{ref}\">#{ref}</a> to <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a>\n"
+ 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 << "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
+ message << "<br /> - #{commit[:message]} (<a href=\"#{commit[:url]}\">#{commit[:id][0..5]}</a>)"
+ end
+ end
+
+ message
+ end
+
+end \ No newline at end of file
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 54d9af7e67e..91dd6477b04 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -25,19 +25,9 @@ class Issue < ActiveRecord::Base
acts_as_taggable_on :labels
- class << self
- def cared(user)
- where('assignee_id = :user', user: user.id)
- end
-
- def authored(user)
- where('author_id = :user', user: user.id)
- end
-
- def open_for(user)
- opened.assigned(user)
- end
- end
+ scope :cared, ->(user) { where(assignee_id: user) }
+ scope :authored, ->(user) { where(author_id: user) }
+ scope :open_for, ->(user) { opened.assigned(user) }
state_machine :state, initial: :opened do
event :close do
@@ -54,4 +44,7 @@ class Issue < ActiveRecord::Base
state :closed
end
+
+ # Both open and reopened issues should be listed as opened
+ scope :opened, -> { with_state(:opened, :reopened) }
end
diff --git a/app/models/key.rb b/app/models/key.rb
index 53eee511e13..185aef46e9e 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -16,20 +16,19 @@ require 'digest/md5'
class Key < ActiveRecord::Base
belongs_to :user
- belongs_to :project
attr_accessible :key, :title
before_validation :strip_white_space
validates :title, presence: true, length: { within: 0..255 }
- validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true
+ validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\Assh-.*\Z/ }, uniqueness: true
validate :fingerprintable_key
delegate :name, :email, to: :user, prefix: true
def strip_white_space
- self.key = self.key.strip unless self.key.blank?
+ self.key = key.strip unless key.blank?
end
def fingerprintable_key
@@ -47,20 +46,12 @@ class Key < ActiveRecord::Base
errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0
end
- def is_deploy_key
- !!project_id
- end
-
# projects that has this key
def projects
- if is_deploy_key
- [project]
- else
- user.authorized_projects
- end
+ user.authorized_projects
end
def shell_id
- "key-#{self.id}"
+ "key-#{id}"
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 9d42b1e1f32..b2ad1b76f1f 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -24,8 +24,6 @@ require Rails.root.join("lib/static_model")
class MergeRequest < ActiveRecord::Base
include Issuable
- BROKEN_DIFF = "--broken-diff"
-
attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id,
:author_id_of_changes, :state_event
@@ -109,22 +107,18 @@ class MergeRequest < ActiveRecord::Base
end
def diffs
- st_diffs || []
+ load_diffs(st_diffs) || []
end
def reloaded_diffs
if opened? && unmerged_diffs.any?
- self.st_diffs = unmerged_diffs
+ self.st_diffs = dump_diffs(unmerged_diffs)
self.save
end
-
- rescue Grit::Git::GitTimeout
- self.st_diffs = [BROKEN_DIFF]
- self.save
end
def broken_diffs?
- diffs == [BROKEN_DIFF]
+ diffs == broken_diffs
end
def valid_diffs?
@@ -132,11 +126,7 @@ class MergeRequest < ActiveRecord::Base
end
def unmerged_diffs
- # Only show what is new in the source branch compared to the target branch, not the other way around.
- # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
- # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
- common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
- diffs = project.repo.diff(common_commit, source_branch)
+ project.repository.diffs_between(source_branch, target_branch)
end
def last_commit
@@ -152,7 +142,7 @@ class MergeRequest < ActiveRecord::Base
end
def commits
- st_commits || []
+ load_commits(st_commits || [])
end
def probably_merged?
@@ -162,16 +152,15 @@ class MergeRequest < ActiveRecord::Base
def reloaded_commits
if opened? && unmerged_commits.any?
- self.st_commits = unmerged_commits
+ self.st_commits = dump_commits(unmerged_commits)
save
end
commits
end
def unmerged_commits
- self.project.repo.
+ self.project.repository.
commits_between(self.target_branch, self.source_branch).
- map {|c| Commit.new(c)}.
sort_by(&:created_at).
reverse
end
@@ -213,4 +202,34 @@ class MergeRequest < ActiveRecord::Base
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 == broken_diffs
+ broken_diffs
+ elsif diffs.respond_to?(:map)
+ diffs.map(&:to_hash)
+ 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) }
+ end
+ end
+
+ def broken_diffs
+ [Gitlab::Git::Diff::BROKEN_DIFF]
+ end
end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 2a9b9e4482c..023b8ddf04d 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -19,6 +19,7 @@ class Milestone < ActiveRecord::Base
belongs_to :project
has_many :issues
has_many :merge_requests
+ has_many :participants, through: :issues, source: :assignee
scope :active, -> { with_state(:active) }
scope :closed, -> { with_state(:closed) }
@@ -48,10 +49,6 @@ class Milestone < ActiveRecord::Base
end
end
- def participants
- User.where(id: issues.pluck(:assignee_id))
- end
-
def open_items_count
self.issues.opened.count + self.merge_requests.opened.count
end
@@ -75,9 +72,9 @@ class Milestone < ActiveRecord::Base
if due_date.past?
"expired at #{due_date.stamp("Aug 21, 2011")}"
else
- "expires at #{due_date.stamp("Aug 21, 2011")}"
+ "expires at #{due_date.stamp("Aug 21, 2011")}"
end
- end
+ end
end
def can_be_closed?
diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb
index d0bc61c3bf7..3cd0c015fa0 100644
--- a/app/models/network/commit.rb
+++ b/app/models/network/commit.rb
@@ -8,7 +8,7 @@ module Network
attr_accessor :time, :spaces, :parent_spaces
def initialize(raw_commit, refs)
- @commit = ::Commit.new(raw_commit)
+ @commit = Gitlab::Git::Commit.new(raw_commit)
@time = -1
@spaces = []
@parent_spaces = []
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
index 2957adbfc19..ffec4712e45 100644
--- a/app/models/network/graph.rb
+++ b/app/models/network/graph.rb
@@ -2,33 +2,42 @@ require "grit"
module Network
class Graph
- attr_reader :days, :commits, :map
+ attr_reader :days, :commits, :map, :notes
def self.max_count
@max_count ||= 650
end
- def initialize project, ref, commit
+ def initialize project, ref, commit, filter_ref
@project = project
@ref = ref
@commit = commit
+ @filter_ref = filter_ref
@repo = project.repo
@commits = collect_commits
@days = index_commits
+ @notes = collect_notes
end
protected
+ def collect_notes
+ h = Hash.new(0)
+ @project.notes.where('noteable_type = ?' ,"Commit").group('notes.commit_id').select('notes.commit_id, count(notes.id) as note_count').each do |item|
+ h[item["commit_id"]] = item["note_count"]
+ end
+ h
+ end
+
# Get commits from repository
#
def collect_commits
refs_cache = build_refs_cache
- find_commits(count_to_display_commit_in_center)
- .map do |commit|
- # Decorate with app/model/network/commit.rb
- Network::Commit.new(commit, refs_cache[commit.id])
+ find_commits(count_to_display_commit_in_center).map do |commit|
+ # Decorate with app/model/network/commit.rb
+ Network::Commit.new(commit, refs_cache[commit.id])
end
end
@@ -93,15 +102,15 @@ module Network
end
def find_commits(skip = 0)
- Grit::Commit.find_all(
- @repo,
- nil,
- {
- date_order: true,
- max_count: self.class.max_count,
- skip: skip
- }
- )
+ opts = {
+ date_order: true,
+ max_count: self.class.max_count,
+ skip: skip
+ }
+
+ ref = @ref if @filter_ref
+
+ Grit::Commit.find_all(@repo, ref, opts)
end
def commits_sort_by_ref
@@ -184,7 +193,7 @@ module Network
l.spaces << space
# Also add space to parent
l.parents(@map).each do |parent|
- if parent.space > 0
+ if 0 < parent.space && parent.space < space
parent.spaces << space
end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 2f3b059918a..9a3481faaaa 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -22,9 +22,6 @@ class Note < ActiveRecord::Base
attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
- attr_accessor :notify
- attr_accessor :notify_author
-
belongs_to :project
belongs_to :noteable, polymorphic: true
belongs_to :author, class_name: "User"
@@ -44,7 +41,7 @@ class Note < ActiveRecord::Base
# Scopes
scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
scope :inline, -> { where("line_code IS NOT NULL") }
- scope :not_inline, -> { where("line_code IS NULL") }
+ scope :not_inline, -> { where(line_code: [nil, '']) }
scope :common, ->{ where(noteable_type: ["", nil]) }
scope :fresh, ->{ order("created_at ASC, id ASC") }
@@ -71,8 +68,8 @@ class Note < ActiveRecord::Base
def diff
if noteable.diffs.present?
noteable.diffs.select do |d|
- if d.b_path
- Digest::SHA1.hexdigest(d.b_path) == diff_file_index
+ if d.new_path
+ Digest::SHA1.hexdigest(d.new_path) == diff_file_index
end
end.first
end
@@ -83,7 +80,7 @@ class Note < ActiveRecord::Base
end
def diff_file_name
- diff.b_path
+ diff.new_path
end
def diff_new_line
@@ -91,7 +88,7 @@ class Note < ActiveRecord::Base
end
def discussion_id
- @discussion_id ||= [:discussion, noteable_type.try(:underscore), noteable_id, line_code].join("-").to_sym
+ @discussion_id ||= [:discussion, noteable_type.try(:underscore), noteable_id || commit_id, line_code].join("-").to_sym
end
# Returns true if this is a downvote note,
@@ -143,14 +140,6 @@ class Note < ActiveRecord::Base
nil
end
- def notify
- @notify ||= false
- end
-
- def notify_author
- @notify_author ||= false
- end
-
# Returns true if this is an upvote note,
# otherwise false is returned
def upvote?
diff --git a/app/models/notification.rb b/app/models/notification.rb
new file mode 100644
index 00000000000..ff6a18d6a51
--- /dev/null
+++ b/app/models/notification.rb
@@ -0,0 +1,39 @@
+class Notification
+ #
+ # Notification levels
+ #
+ N_DISABLED = 0
+ N_PARTICIPATING = 1
+ N_WATCH = 2
+ N_GLOBAL = 3
+
+ 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]
+ end
+
+ def initialize(target)
+ @target = target
+ end
+
+ def disabled?
+ target.notification_level == N_DISABLED
+ end
+
+ def participating?
+ target.notification_level == N_PARTICIPATING
+ end
+
+ def watch?
+ target.notification_level == N_WATCH
+ end
+
+ def global?
+ target.notification_level == N_GLOBAL
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index a0f014a15ab..8cb290f6601 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -18,6 +18,8 @@
# public :boolean default(FALSE), not null
# issues_tracker :string(255) default("gitlab"), not null
# issues_tracker_id :string(255)
+# snippets_enabled :boolean default(TRUE), not null
+# last_activity_at :datetime
#
require "grit"
@@ -26,14 +28,14 @@ class Project < ActiveRecord::Base
include Gitlab::ShellAdapter
extend Enumerize
- class TransferError < StandardError; end
-
- attr_accessible :name, :path, :description, :default_branch, :issues_tracker,
+ attr_accessible :name, :path, :description, :default_branch, :issues_tracker, :label_list,
:issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
- :wiki_enabled, :public, :import_url, as: [:default, :admin]
+ :wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin]
attr_accessible :namespace_id, :creator_id, as: :admin
+ acts_as_taggable_on :labels, :issues_default_labels
+
attr_accessor :import_url
# Relations
@@ -43,7 +45,12 @@ class Project < ActiveRecord::Base
has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id'
has_one :gitlab_ci_service, dependent: :destroy
+ has_one :campfire_service, dependent: :destroy
+ has_one :hipchat_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
+ has_many :services, dependent: :destroy
has_many :events, dependent: :destroy
has_many :merge_requests, dependent: :destroy
has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
@@ -51,9 +58,7 @@ class Project < ActiveRecord::Base
has_many :users_projects, dependent: :destroy
has_many :notes, dependent: :destroy
has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet"
- has_many :deploy_keys, dependent: :destroy, class_name: "Key", foreign_key: "project_id"
has_many :hooks, dependent: :destroy, class_name: "ProjectHook"
- has_many :wikis, dependent: :destroy
has_many :protected_branches, dependent: :destroy
has_many :user_team_project_relationships, dependent: :destroy
@@ -62,6 +67,9 @@ class Project < ActiveRecord::Base
has_many :user_team_user_relationships, through: :user_teams
has_many :user_teams_members, through: :user_team_user_relationships
+ has_many :deploy_keys_projects, dependent: :destroy
+ has_many :deploy_keys, through: :deploy_keys_projects
+
delegate :name, to: :owner, allow_nil: true, prefix: true
# Validations
@@ -87,17 +95,18 @@ class Project < ActiveRecord::Base
validate :check_limit, :repo_name
# Scopes
- scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
- scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) }
- scope :without_team, ->(team) { team.projects.present? ? where("id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped }
- scope :in_team, ->(team) { where("id IN (:ids)", ids: team.projects.map(&:id)) }
+ scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
+ scope :without_team, ->(team) { team.projects.present? ? where("projects.id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped }
+ scope :not_in_group, ->(group) { where("projects.id NOT IN (:ids)", ids: group.project_ids ) }
+ scope :in_team, ->(team) { where("projects.id IN (:ids)", ids: team.projects.map(&:id)) }
scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
- scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") }
+ scope :in_group_namespace, -> { joins(:group) }
+ scope :sorted_by_activity, -> { order("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(public: true) }
- enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab
+ enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
class << self
def abandoned
@@ -142,13 +151,7 @@ class Project < ActiveRecord::Base
end
def repository
- if path
- @repository ||= Repository.new(path_with_namespace, default_branch)
- else
- nil
- end
- rescue Grit::NoSuchPathError
- nil
+ @repository ||= Repository.new(path_with_namespace, default_branch)
end
def saved?
@@ -196,7 +199,7 @@ class Project < ActiveRecord::Base
end
def last_activity_date
- last_event.try(:created_at) || updated_at
+ last_activity_at || updated_at
end
def project_id
@@ -204,7 +207,7 @@ class Project < ActiveRecord::Base
end
def issues_labels
- issues.tag_counts_on(:labels)
+ @issues_labels ||= (issues_default_labels + issues.tags_on(:labels)).uniq.sort_by(&:name)
end
def issue_exists?(issue_id)
@@ -223,8 +226,18 @@ class Project < ActiveRecord::Base
self.issues_enabled && !self.used_default_issues_tracker?
end
- def services
- [gitlab_ci_service].compact
+ def build_missing_services
+ available_services_names.each do |service_name|
+ service = services.find { |service| service.to_param == service_name }
+
+ # If service is available but missing in db
+ # we should create an instance. Ex `create_gitlab_ci_service`
+ service = self.send :"create_#{service_name}_service" if service.nil?
+ end
+ end
+
+ def available_services_names
+ %w(gitlab_ci campfire hipchat)
end
def gitlab_ci?
@@ -333,14 +346,14 @@ class Project < ActiveRecord::Base
end
def valid_repo?
- repo
+ repository.exists?
rescue
errors.add(:path, "Invalid repository path")
false
end
def empty_repo?
- !repository || repository.empty?
+ !repository.exists? || repository.empty?
end
def ensure_satellite_exists
@@ -364,18 +377,25 @@ class Project < ActiveRecord::Base
end
def repo_exists?
- @repo_exists ||= (repository && repository.branches.present?)
+ @repo_exists ||= repository.exists?
rescue
@repo_exists = false
end
def open_branches
- if protected_branches.empty?
- self.repo.heads
- else
- pnames = protected_branches.map(&:name)
- self.repo.heads.reject { |h| pnames.include?(h.name) }
- end.sort_by(&:name)
+ all_branches = repository.branches
+
+ if protected_branches.present?
+ all_branches.reject! do |branch|
+ protected_branches_names.include?(branch.name)
+ end
+ end
+
+ all_branches
+ end
+
+ def protected_branches_names
+ @protected_branches_names ||= protected_branches.map(&:name)
end
def root_ref?(branch)
@@ -397,6 +417,34 @@ class Project < ActiveRecord::Base
# Check if current branch name is marked as protected in the system
def protected_branch? branch_name
- protected_branches.map(&:name).include?(branch_name)
+ protected_branches_names.include?(branch_name)
+ end
+
+ def forked?
+ !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
+ end
+
+ def rename_repo
+ old_path_with_namespace = File.join(namespace_dir, path_was)
+ new_path_with_namespace = File.join(namespace_dir, path)
+
+ if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
+ # If repository moved successfully we need to remove old satellite
+ # and send update instructions to users.
+ # However we cannot allow rollback since we moved repository
+ # So we basically we mute exceptions in next actions
+ begin
+ gitlab_shell.rm_satellites(old_path_with_namespace)
+ send_move_instructions
+ rescue
+ # Returning false does not rolback after_* transaction but gives
+ # us information about failing some of tasks
+ false
+ end
+ else
+ # if we cannot move namespace directory we should rollback
+ # db changes in order to prevent out of sync between db and fs
+ raise Exception.new('repository cannot be renamed')
+ end
end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 934c1a6e086..daf176576ad 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1,169 +1,75 @@
class Repository
- include Gitlab::Popen
+ attr_accessor :raw_repository
- # Repository directory name with namespace direcotry
- # Examples:
- # gitlab/gitolite
- # diaspora
- #
- attr_accessor :path_with_namespace
-
- # Grit repo object
- attr_accessor :repo
-
- # Default branch in the repository
- attr_accessor :root_ref
-
- def initialize(path_with_namespace, root_ref = 'master')
- @root_ref = root_ref || "master"
- @path_with_namespace = path_with_namespace
-
- # Init grit repo object
- repo
- end
-
- def raw
- repo
+ def initialize(path_with_namespace, default_branch)
+ @raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch)
+ rescue Gitlab::Git::Repository::NoRepository
+ nil
end
- def path_to_repo
- @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
+ def exists?
+ raw_repository
end
- def repo
- @repo ||= Grit::Repo.new(path_to_repo)
- end
-
- def commit(commit_id = nil)
- Commit.find_or_first(repo, commit_id, root_ref)
- end
-
- def fresh_commits(n = 10)
- Commit.fresh_commits(repo, n)
- end
-
- def commits_with_refs(n = 20)
- Commit.commits_with_refs(repo, n)
+ def empty?
+ raw_repository.empty?
end
- def commits_since(date)
- Commit.commits_since(repo, date)
+ def commit(id = nil)
+ commit = raw_repository.commit(id)
+ commit = Commit.new(commit) if commit
+ commit
end
def commits(ref, path = nil, limit = nil, offset = nil)
- Commit.commits(repo, ref, path, limit, offset)
+ commits = raw_repository.commits(ref, path, limit, offset)
+ commits = Commit.decorate(commits) if commits.present?
+ commits
end
- def last_commit_for(ref, path = nil)
- commits(ref, path, 1).first
+ def commits_between(target, source)
+ commits = raw_repository.commits_between(target, source)
+ commits = Commit.decorate(commits) if commits.present?
+ commits
end
- def commits_between(from, to)
- Commit.commits_between(repo, from, to)
- end
-
- # Returns an Array of branch names
def branch_names
- repo.branches.collect(&:name).sort
- end
-
- # Returns an Array of Branches
- def branches
- repo.branches.sort_by(&:name)
+ Rails.cache.fetch(cache_key(:branch_names)) do
+ raw_repository.branch_names
+ end
end
- # Returns an Array of tag names
def tag_names
- repo.tags.collect(&:name).sort.reverse
- end
-
- # Returns an Array of Tags
- def tags
- repo.tags.sort_by(&:name).reverse
- end
-
- # Returns an Array of branch and tag names
- def ref_names
- [branch_names + tag_names].flatten
- end
-
- def heads
- @heads ||= repo.heads
- end
-
- def tree(fcommit, path = nil)
- fcommit = commit if fcommit == :head
- tree = fcommit.tree
- path ? (tree / path) : tree
- end
-
- def has_commits?
- !!commit
- rescue Grit::NoSuchPathError
- false
- end
-
- def empty?
- !has_commits?
- end
-
- # Discovers the default branch based on the repository's available branches
- #
- # - If no branches are present, returns nil
- # - If one branch is present, returns its name
- # - If two or more branches are present, returns the one that has a name
- # matching root_ref (default_branch or 'master' if default_branch is nil)
- def discover_default_branch
- if branch_names.length == 0
- nil
- elsif branch_names.length == 1
- branch_names.first
- else
- branch_names.select { |v| v == root_ref }.first
+ Rails.cache.fetch(cache_key(:tag_names)) do
+ raw_repository.tag_names
end
end
- # Archive Project to .tar.gz
- #
- # Already packed repo archives stored at
- # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
- #
- def archive_repo(ref)
- ref = ref || self.root_ref
- commit = self.commit(ref)
- return nil unless commit
-
- # Build file path
- file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
- storage_path = Rails.root.join("tmp", "repositories")
- file_path = File.join(storage_path, self.path_with_namespace, file_name)
-
- # Put files into a directory before archiving
- prefix = File.basename(self.path_with_namespace) + "/"
-
- # Create file if not exists
- unless File.exists?(file_path)
- FileUtils.mkdir_p File.dirname(file_path)
- file = self.repo.archive_to_file(ref, prefix, file_path)
- end
-
- file_path
+ def method_missing(m, *args, &block)
+ raw_repository.send(m, *args, &block)
end
# Return repo size in megabytes
# Cached in redis
def size
Rails.cache.fetch(cache_key(:size)) do
- size = popen('du -s', path_to_repo).first.strip.to_i
- (size.to_f / 1024).round(2)
+ raw_repository.size
end
end
def expire_cache
Rails.cache.delete(cache_key(:size))
+ Rails.cache.delete(cache_key(:branch_names))
+ Rails.cache.delete(cache_key(:tag_names))
end
def cache_key(type)
"#{type}:#{path_with_namespace}"
end
+
+ def respond_to?(method)
+ return true if raw_repository.respond_to?(method)
+
+ super
+ end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index d3486d29200..3e945aa898c 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -13,6 +13,8 @@
# project_url :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
@@ -24,4 +26,25 @@ class Service < ActiveRecord::Base
def activated?
active
end
+
+ def title
+ # implement inside child
+ end
+
+ def description
+ # implement inside child
+ end
+
+ def to_param
+ # implement inside child
+ end
+
+ def fields
+ # implement inside child
+ []
+ end
+
+ def execute
+ # implement inside child
+ end
end
diff --git a/app/models/tree.rb b/app/models/tree.rb
index 96395a42394..042050527c1 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -1,29 +1,17 @@
class Tree
- include Linguist::BlobHelper
+ attr_accessor :raw
- attr_accessor :path, :tree, :ref
-
- delegate :contents, :basename, :name, :data, :mime_type,
- :mode, :size, :text?, :colorize, to: :tree
-
- def initialize(raw_tree, ref = nil, path = nil)
- @ref, @path = ref, path
- @tree = if path.present?
- raw_tree / path
- else
- raw_tree
- end
+ def initialize(repository, sha, ref = nil, path = nil)
+ @raw = Gitlab::Git::Tree.new(repository, sha, ref, path)
end
- def is_blob?
- tree.is_a?(Grit::Blob)
+ def method_missing(m, *args, &block)
+ @raw.send(m, *args, &block)
end
- def invalid?
- tree.nil?
- end
+ def respond_to?(method)
+ return true if @raw.respond_to?(method)
- def empty?
- data.blank?
+ super
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index e6ab66f4bc7..0aed0ada757 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -33,6 +33,7 @@
# can_create_team :boolean default(TRUE), not null
# state :string(255)
# color_scheme_id :integer default(1), not null
+# notification_level :integer default(1), not null
#
class User < ActiveRecord::Base
@@ -46,16 +47,22 @@ class User < ActiveRecord::Base
attr_accessor :force_random_password
+ # Virtual attribute for authenticating by either username or email
+ attr_accessor :login
+
+ # Add login to attr_accessible
+ attr_accessible :login
+
+
#
# Relations
#
# Namespace for personal projects
- has_one :namespace,
- dependent: :destroy,
- foreign_key: :owner_id,
- class_name: "Namespace",
- conditions: 'type IS NULL'
+ has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL'
+
+ # Namespaces (owned groups and own namespace)
+ has_many :namespaces, foreign_key: :owner_id
# Profile
has_many :keys, dependent: :destroy
@@ -64,15 +71,11 @@ class User < ActiveRecord::Base
has_many :groups, class_name: "Group", foreign_key: :owner_id
# Teams
- has_many :own_teams,
- class_name: "UserTeam",
- foreign_key: :owner_id,
- dependent: :destroy
-
- has_many :user_team_user_relationships, dependent: :destroy
- has_many :user_teams, through: :user_team_user_relationships
+ has_many :own_teams, dependent: :destroy, class_name: "UserTeam", foreign_key: :owner_id
+ has_many :user_team_user_relationships, dependent: :destroy
+ has_many :user_teams, through: :user_team_user_relationships
has_many :user_team_project_relationships, through: :user_teams
- has_many :team_projects, through: :user_team_project_relationships
+ has_many :team_projects, through: :user_team_project_relationships
# Projects
has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet"
@@ -81,14 +84,14 @@ class User < ActiveRecord::Base
has_many :notes, dependent: :destroy, foreign_key: :author_id
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
+ has_many :recent_events, foreign_key: :author_id, class_name: "Event", order: "id DESC"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
- has_many :projects, through: :users_projects
- has_many :recent_events,
- class_name: "Event",
- foreign_key: :author_id,
- order: "id DESC"
+ has_many :personal_projects, through: :namespace, source: :projects
+ has_many :projects, through: :users_projects
+ has_many :own_projects, foreign_key: :creator_id, class_name: 'Project'
+ has_many :owned_projects, through: :namespaces, source: :projects
#
# Validations
@@ -102,6 +105,7 @@ class User < ActiveRecord::Base
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
+ validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
@@ -135,12 +139,25 @@ class User < ActiveRecord::Base
scope :alphabetically, -> { order('name ASC') }
scope :in_team, ->(team){ where(id: team.member_ids) }
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
+ scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : scoped }
+ scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') }
+
scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
#
# Class methods
#
class << self
+ # Devise method overriden to allow sing in with email or username
+ def find_for_database_authentication(warden_conditions)
+ conditions = warden_conditions.dup
+ if login = conditions.delete(:login)
+ where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first
+ else
+ where(conditions).first
+ end
+ end
+
def filter filter_name
case filter_name
when "admins"; self.admins
@@ -151,18 +168,6 @@ class User < ActiveRecord::Base
end
end
- def not_in_project(project)
- if project.users.present?
- where("id not in (:ids)", ids: project.users.map(&:id) )
- else
- scoped
- end
- end
-
- def without_projects
- where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
- end
-
def create_from_omniauth(auth, ldap = false)
gitlab_auth.create_from_omniauth(auth, ldap)
end
@@ -192,6 +197,18 @@ class User < ActiveRecord::Base
username
end
+ def with_defaults
+ tap do |u|
+ u.projects_limit = Gitlab.config.gitlab.default_projects_limit
+ u.can_create_group = Gitlab.config.gitlab.default_can_create_group
+ u.can_create_team = Gitlab.config.gitlab.default_can_create_team
+ end
+ end
+
+ def notification
+ @notification ||= Notification.new(self)
+ end
+
def generate_password
if self.force_random_password
self.password = self.password_confirmation = Devise.friendly_token.first(8)
@@ -205,56 +222,36 @@ class User < ActiveRecord::Base
end
end
- # Namespaces user has access to
- def namespaces
- namespaces = []
-
- # Add user account namespace
- namespaces << self.namespace if self.namespace
-
- # Add groups you can manage
- namespaces += groups.all
-
- namespaces
- end
-
# Groups where user is an owner
def owned_groups
groups
end
+ def owned_teams
+ own_teams
+ end
+
# Groups user has access to
def authorized_groups
- @authorized_groups ||= begin
- groups = Group.where(id: self.authorized_projects.pluck(:namespace_id)).all
- groups = groups + self.groups
- groups.uniq
- end
+ @group_ids ||= (groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
+ Group.where(id: @group_ids)
end
# Projects user has access to
def authorized_projects
- project_ids = users_projects.pluck(:project_id)
- project_ids = project_ids | owned_projects.pluck(:id)
- Project.where(id: project_ids)
- end
-
- # Projects in user namespace
- def personal_projects
- Project.personal(self)
+ @project_ids ||= (owned_projects.pluck(:id) + projects.pluck(:id)).uniq
+ Project.where(id: @project_ids)
end
- # Projects where user is an owner
- def owned_projects
- Project.where("(projects.namespace_id IN (:namespaces)) OR
- (projects.namespace_id IS NULL AND projects.creator_id = :user_id)",
- namespaces: namespaces.map(&:id), user_id: self.id)
+ def authorized_teams
+ @team_ids ||= (user_teams.pluck(:id) + own_teams.pluck(:id)).uniq
+ UserTeam.where(id: @team_ids)
end
# Team membership in authorized projects
def tm_in_authorized_projects
- UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id)
+ UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id)
end
def is_admin?
@@ -301,9 +298,13 @@ class User < ActiveRecord::Base
MergeRequest.cared(self)
end
+ def projects_limit_left
+ projects_limit - owned_projects.count
+ end
+
def projects_limit_percent
return 100 if projects_limit.zero?
- (personal_projects.count.to_f / projects_limit) * 100
+ (owned_projects.count.to_f / projects_limit) * 100
end
def recent_push project_id = nil
@@ -320,29 +321,40 @@ class User < ActiveRecord::Base
end
def several_namespaces?
- namespaces.size > 1
+ namespaces.many?
end
def namespace_id
namespace.try :id
end
- def authorized_teams
- @authorized_teams ||= begin
- ids = []
- ids << UserTeam.with_member(self).pluck('user_teams.id')
- ids << UserTeam.created_by(self).pluck('user_teams.id')
- ids.flatten
+ def name_with_username
+ "#{name} (#{username})"
+ end
- UserTeam.where(id: ids)
- end
+ def tm_of(project)
+ project.team_member_by_id(self.id)
end
- def owned_teams
- UserTeam.where(owner_id: self.id)
+ def already_forked? project
+ !!fork_of(project)
end
- def name_with_username
- "#{name} (#{username})"
+ def fork_of project
+ links = ForkedProjectLink.where(forked_from_project_id: project, forked_to_project_id: personal_projects)
+
+ if links.any?
+ links.first.forked_to_project
+ else
+ nil
+ end
+ end
+
+ def ldap_user?
+ extern_uid && provider == 'ldap'
+ end
+
+ def owned_deploy_keys
+ DeployKey.in_projects(self.owned_projects).uniq
end
end
diff --git a/app/models/user_team.rb b/app/models/user_team.rb
index 5de2ac6ae9e..364ea0d7dd1 100644
--- a/app/models/user_team.rb
+++ b/app/models/user_team.rb
@@ -113,5 +113,4 @@ class UserTeam < ActiveRecord::Base
def admin?(member)
user_team_user_relationships.with_user(member).first.group_admin?
end
-
end
diff --git a/app/models/users_project.rb b/app/models/users_project.rb
index 8051c0604d9..935ecede42c 100644
--- a/app/models/users_project.rb
+++ b/app/models/users_project.rb
@@ -2,12 +2,13 @@
#
# Table name: users_projects
#
-# id :integer not null, primary key
-# user_id :integer not null
-# project_id :integer not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# project_access :integer default(0), not null
+# id :integer not null, primary key
+# user_id :integer not null
+# project_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# project_access :integer default(0), not null
+# notification_level :integer default(3), not null
#
class UsersProject < ActiveRecord::Base
@@ -29,6 +30,7 @@ class UsersProject < ActiveRecord::Base
validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true
validates :project, presence: true
+ validates :notification_level, inclusion: { in: Notification.project_notification_levels }, presence: true
delegate :name, :username, :email, to: :user, prefix: true
@@ -38,7 +40,7 @@ class UsersProject < ActiveRecord::Base
scope :masters, -> { where(project_access: MASTER) }
scope :in_project, ->(project) { where(project_id: project.id) }
- scope :in_projects, ->(projects) { where(project_id: project_ids) }
+ scope :in_projects, ->(projects) { where(project_id: projects.map { |p| p.id }) }
scope :with_user, ->(user) { where(user_id: user.id) }
class << self
@@ -134,4 +136,8 @@ class UsersProject < ActiveRecord::Base
def skip_git?
!!@skip_git
end
+
+ def notification
+ @notification ||= Notification.new(self)
+ end
end
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
deleted file mode 100644
index 7f488ca7625..00000000000
--- a/app/models/wiki.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# == Schema Information
-#
-# Table name: wikis
-#
-# id :integer not null, primary key
-# title :string(255)
-# content :text
-# project_id :integer
-# created_at :datetime not null
-# updated_at :datetime not null
-# slug :string(255)
-# user_id :integer
-#
-
-class Wiki < ActiveRecord::Base
- attr_accessible :title, :content, :slug
-
- belongs_to :project
- belongs_to :user
- has_many :notes, as: :noteable, dependent: :destroy
-
- validates :content, presence: true
- validates :user, presence: true
- validates :title, presence: true, length: 1..250
-
- before_update :set_slug
-
- scope :ordered, order("created_at DESC")
-
- def to_param
- slug
- end
-
- class << self
- def search(query)
- where("title like :query OR content like :query", query: "%#{query}%")
- end
- end
-
- protected
-
- def self.regenerate_from wiki
- regenerated_field = [:slug, :content, :title]
-
- new_wiki = Wiki.new
- regenerated_field.each do |field|
- new_wiki.send("#{field}=", wiki.send(field))
- end
- new_wiki
- end
-
- def set_slug
- self.slug = self.title.parameterize
- end
-end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index adc77b22231..497d69e8e90 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -79,14 +79,14 @@ class WikiPage
def version
return nil unless persisted?
- @version ||= Commit.new(@page.version)
+ @version ||= Commit.new(Gitlab::Git::Commit.new(@page.version))
end
# Returns an array of Gitlab Commit instances.
def versions
return [] unless persisted?
- @page.versions.map { |v| Commit.new(v) }
+ @page.versions.map { |v| Commit.new(Gitlab::Git::Commit.new(v)) }
end
# Returns the Date that this latest version was
diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb
index c040c4c5ca2..ee3e4629b4c 100644
--- a/app/observers/activity_observer.rb
+++ b/app/observers/activity_observer.rb
@@ -1,4 +1,4 @@
-class ActivityObserver < ActiveRecord::Observer
+class ActivityObserver < BaseObserver
observe :issue, :merge_request, :note, :milestone
def after_create(record)
diff --git a/app/observers/base_observer.rb b/app/observers/base_observer.rb
new file mode 100644
index 00000000000..182d3b7b73c
--- /dev/null
+++ b/app/observers/base_observer.rb
@@ -0,0 +1,9 @@
+class BaseObserver < ActiveRecord::Observer
+ def notification
+ NotificationService.new
+ end
+
+ def log_info message
+ Gitlab::AppLogger.info message
+ end
+end
diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb
index 29e24040378..03ce4b95ac8 100644
--- a/app/observers/issue_observer.rb
+++ b/app/observers/issue_observer.rb
@@ -1,42 +1,30 @@
-class IssueObserver < ActiveRecord::Observer
+class IssueObserver < BaseObserver
cattr_accessor :current_user
def after_create(issue)
- if issue.assignee && issue.assignee != current_user
- Notify.delay.new_issue_email(issue.id)
- end
+ notification.new_issue(issue, current_user)
end
def after_close(issue, transition)
- send_reassigned_email(issue) if issue.is_being_reassigned?
+ notification.close_issue(issue, current_user)
create_note(issue)
end
def after_reopen(issue, transition)
- send_reassigned_email(issue) if issue.is_being_reassigned?
-
create_note(issue)
end
def after_update(issue)
- send_reassigned_email(issue) if issue.is_being_reassigned?
+ if issue.is_being_reassigned?
+ notification.reassigned_issue(issue, current_user)
+ end
end
protected
+ # Create issue note with service comment like 'Status changed to closed'
def create_note(issue)
Note.create_status_change_note(issue, current_user, issue.state)
- [issue.author, issue.assignee].compact.uniq.each do |recipient|
- Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id)
- end
- end
-
- def send_reassigned_email(issue)
- recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id }
-
- recipient_ids.each do |recipient_id|
- Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was)
- end
end
end
diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb
index 0bc71a663e8..28fef55abf9 100644
--- a/app/observers/key_observer.rb
+++ b/app/observers/key_observer.rb
@@ -1,6 +1,4 @@
-class KeyObserver < ActiveRecord::Observer
- include Gitlab::ShellAdapter
-
+class KeyObserver < BaseObserver
def after_save(key)
GitlabShellWorker.perform_async(
:add_key,
@@ -8,8 +6,7 @@ class KeyObserver < ActiveRecord::Observer
key.key
)
- # Notify about ssh key being added
- Notify.delay.new_ssh_key_email(key.id) if key.user
+ notification.new_key(key)
end
def after_destroy(key)
diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb
index d89e7734c1a..d0dfad8869d 100644
--- a/app/observers/merge_request_observer.rb
+++ b/app/observers/merge_request_observer.rb
@@ -1,36 +1,25 @@
-class MergeRequestObserver < ActiveRecord::Observer
+class MergeRequestObserver < BaseObserver
cattr_accessor :current_user
def after_create(merge_request)
- if merge_request.assignee && merge_request.assignee != current_user
- Notify.delay.new_merge_request_email(merge_request.id)
- end
+ notification.new_merge_request(merge_request, current_user)
end
def after_close(merge_request, transition)
- send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
-
Note.create_status_change_note(merge_request, current_user, merge_request.state)
+
+ notification.close_mr(merge_request, current_user)
end
- def after_reopen(merge_request, transition)
- send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
+ def after_merge(merge_request, transition)
+ notification.merge_mr(merge_request)
+ end
+ def after_reopen(merge_request, transition)
Note.create_status_change_note(merge_request, current_user, merge_request.state)
end
def after_update(merge_request)
- send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
- end
-
- protected
-
- def send_reassigned_email(merge_request)
- recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id
- recipients_ids.delete current_user.id
-
- recipients_ids.each do |recipient_id|
- Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was)
- end
+ notification.reassigned_merge_request(merge_request, current_user) if merge_request.is_being_reassigned?
end
end
diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb
index 0f820a263b3..7b79161cce4 100644
--- a/app/observers/note_observer.rb
+++ b/app/observers/note_observer.rb
@@ -1,38 +1,5 @@
-class NoteObserver < ActiveRecord::Observer
+class NoteObserver < BaseObserver
def after_create(note)
- send_notify_mails(note)
- end
-
- protected
-
- def send_notify_mails(note)
- if note.notify
- notify_team(note)
- elsif note.notify_author
- # Notify only author of resource
- if note.commit_author
- Notify.delay.note_commit_email(note.commit_author.id, note.id)
- end
- else
- # Otherwise ignore it
- nil
- end
- end
-
- # Notifies the whole team except the author of note
- def notify_team(note)
- # Note: wall posts are not "attached" to anything, so fall back to "Wall"
- noteable_type = note.noteable_type.presence || "Wall"
- notify_method = "note_#{noteable_type.underscore}_email".to_sym
-
- if Notify.respond_to? notify_method
- team_without_note_author(note).map do |u|
- Notify.delay.send(notify_method, u.id, note.id)
- end
- end
- end
-
- def team_without_note_author(note)
- note.project.users.reject { |u| u.id == note.author.id }
+ notification.new_note(note)
end
end
diff --git a/app/observers/project_activity_cache_observer.rb b/app/observers/project_activity_cache_observer.rb
new file mode 100644
index 00000000000..96ced90db80
--- /dev/null
+++ b/app/observers/project_activity_cache_observer.rb
@@ -0,0 +1,8 @@
+class ProjectActivityCacheObserver < BaseObserver
+ observe :event
+
+ def after_create(event)
+ event.project.update_column(:last_activity_at, event.created_at) if event.project
+ end
+end
+
diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb
index 89dc97ac140..bd88bb838ef 100644
--- a/app/observers/project_observer.rb
+++ b/app/observers/project_observer.rb
@@ -1,15 +1,22 @@
-class ProjectObserver < ActiveRecord::Observer
+class ProjectObserver < BaseObserver
def after_create(project)
- GitlabShellWorker.perform_async(
- :add_repository,
- project.path_with_namespace
- )
-
- log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
+ unless project.forked?
+ GitlabShellWorker.perform_async(
+ :add_repository,
+ project.path_with_namespace
+ )
+
+ log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
+ end
end
def after_update(project)
project.send_move_instructions if project.namespace_id_changed?
+ project.rename_repo if project.path_changed?
+ end
+
+ def before_destroy(project)
+ project.repository.expire_cache unless project.empty_repo?
end
def after_destroy(project)
@@ -27,10 +34,4 @@ class ProjectObserver < ActiveRecord::Observer
log_info("Project \"#{project.name}\" was removed")
end
-
- protected
-
- def log_info message
- Gitlab::AppLogger.info message
- end
end
diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb
index be2594b4916..3a649fd590d 100644
--- a/app/observers/system_hook_observer.rb
+++ b/app/observers/system_hook_observer.rb
@@ -1,4 +1,4 @@
-class SystemHookObserver < ActiveRecord::Observer
+class SystemHookObserver < BaseObserver
observe :user, :project, :users_project
def after_create(model)
diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb
index 6c461e07865..6bb3c471d0c 100644
--- a/app/observers/user_observer.rb
+++ b/app/observers/user_observer.rb
@@ -1,9 +1,8 @@
-class UserObserver < ActiveRecord::Observer
+class UserObserver < BaseObserver
def after_create(user)
log_info("User \"#{user.name}\" (#{user.email}) was created")
- # Dont email omniauth created users
- Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid?
+ notification.new_user(user)
end
def after_destroy user
@@ -19,10 +18,4 @@ class UserObserver < ActiveRecord::Observer
end
end
end
-
- protected
-
- def log_info message
- Gitlab::AppLogger.info message
- end
end
diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb
index 66b421753f0..ca9649c76ab 100644
--- a/app/observers/users_project_observer.rb
+++ b/app/observers/users_project_observer.rb
@@ -1,7 +1,6 @@
-class UsersProjectObserver < ActiveRecord::Observer
+class UsersProjectObserver < BaseObserver
def after_commit(users_project)
return if users_project.destroyed?
- Notify.delay.project_access_granted_email(users_project.id)
end
def after_create(users_project)
@@ -10,6 +9,12 @@ class UsersProjectObserver < ActiveRecord::Observer
action: Event::JOINED,
author_id: users_project.user.id
)
+
+ notification.new_team_member(users_project)
+ end
+
+ def after_update(users_project)
+ notification.update_team_member(users_project)
end
def after_destroy(users_project)
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 383e6398b74..e8b32f52ce1 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -104,7 +104,7 @@ class GitPushService
data[:commits] << {
id: commit.id,
message: commit.safe_message,
- timestamp: commit.date.xmlschema,
+ timestamp: commit.committed_date.xmlschema,
url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}",
author: {
name: commit.author_name,
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
new file mode 100644
index 00000000000..379d2c54629
--- /dev/null
+++ b/app/services/notification_service.rb
@@ -0,0 +1,223 @@
+# NotificationService class
+#
+# Used for notifing users with emails about different events
+#
+# Ex.
+# NotificationService.new.new_issue(issue, current_user)
+#
+class NotificationService
+ # Always notify user about ssh key added
+ # only if ssh key is not deploy key
+ #
+ # This is security email so it will be sent
+ # even if user disabled notifications
+ def new_key(key)
+ if key.user
+ mailer.new_ssh_key_email(key.id)
+ end
+ end
+
+ # When create an issue we should send next emails:
+ #
+ # * issue assignee if his notification level is not Disabled
+ # * project team members with notification level higher then Participating
+ #
+ def new_issue(issue, current_user)
+ new_resource_email(issue, 'new_issue_email')
+ end
+
+ # When we close an issue we should send next emails:
+ #
+ # * issue author if his notification level is not Disabled
+ # * issue assignee if his notification level is not Disabled
+ # * project team members with notification level higher then Participating
+ #
+ def close_issue(issue, current_user)
+ close_resource_email(issue, current_user, 'closed_issue_email')
+ end
+
+ # When we reassign an issue we should send next emails:
+ #
+ # * issue old assignee if his notification level is not Disabled
+ # * issue new assignee if his notification level is not Disabled
+ #
+ def reassigned_issue(issue, current_user)
+ reassign_resource_email(issue, current_user, 'reassigned_issue_email')
+ end
+
+
+ # When create a merge request we should send next emails:
+ #
+ # * mr assignee if his notification level is not Disabled
+ #
+ def new_merge_request(merge_request, current_user)
+ new_resource_email(merge_request, 'new_merge_request_email')
+ end
+
+ # When we reassign a merge_request we should send next emails:
+ #
+ # * merge_request old assignee if his notification level is not Disabled
+ # * merge_request assignee if his notification level is not Disabled
+ #
+ def reassigned_merge_request(merge_request, current_user)
+ reassign_resource_email(merge_request, current_user, 'reassigned_merge_request_email')
+ end
+
+ # When we close a merge request we should send next emails:
+ #
+ # * merge_request author if his notification level is not Disabled
+ # * merge_request assignee if his notification level is not Disabled
+ # * project team members with notification level higher then Participating
+ #
+ def close_mr(merge_request, current_user)
+ close_resource_email(merge_request, current_user, 'closed_merge_request_email')
+ end
+
+ # When we merge a merge request we should send next emails:
+ #
+ # * merge_request author if his notification level is not Disabled
+ # * merge_request assignee if his notification level is not Disabled
+ # * project team members with notification level higher then Participating
+ #
+ def merge_mr(merge_request)
+ recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.project)
+ recipients = recipients.concat(project_watchers(merge_request.project)).uniq
+
+ recipients.each do |recipient|
+ mailer.merged_merge_request_email(recipient.id, merge_request.id)
+ end
+ end
+
+ # Notify new user with email after creation
+ def new_user(user)
+ # Dont email omniauth created users
+ mailer.new_user_email(user.id, user.password) unless user.extern_uid?
+ end
+
+ # Notify users on new note in system
+ #
+ # TODO: split on methods and refactor
+ #
+ def new_note(note)
+ # ignore wall messages
+ return true unless note.noteable_type.present?
+
+ opts = { noteable_type: note.noteable_type, project_id: note.project_id }
+
+ if note.commit_id.present?
+ opts.merge!(commit_id: note.commit_id)
+ recipients = [note.commit_author]
+ else
+ opts.merge!(noteable_id: note.noteable_id)
+ target = note.noteable
+ recipients = []
+ recipients << target.assignee if target.respond_to?(:assignee)
+ recipients << target.author if target.respond_to?(:author)
+ end
+
+ # Get users who left comment in thread
+ recipients = recipients.concat(User.where(id: Note.where(opts).pluck(:author_id)))
+
+ # Merge project watchers
+ recipients = recipients.concat(project_watchers(note.project)).compact.uniq
+
+ # Reject mutes users
+ recipients = reject_muted_users(recipients, note.project)
+
+ # Reject author
+ recipients.delete(note.author)
+
+ # build notify method like 'note_commit_email'
+ notify_method = "note_#{note.noteable_type.underscore}_email".to_sym
+
+ recipients.each do |recipient|
+ mailer.send(notify_method, recipient.id, note.id)
+ end
+ end
+
+ def new_team_member(users_project)
+ mailer.project_access_granted_email(users_project.id)
+ end
+
+ def update_team_member(users_project)
+ mailer.project_access_granted_email(users_project.id)
+ end
+
+ protected
+
+ # Get project users with WATCH notification level
+ def project_watchers(project)
+
+ # Get project notification settings since it has higher priority
+ user_ids = project.users_projects.where(notification_level: Notification::N_WATCH).pluck(:user_id)
+ project_watchers = User.where(id: user_ids)
+
+ # next collect users who use global settings with watch state
+ user_ids = project.users_projects.where(notification_level: Notification::N_GLOBAL).pluck(:user_id)
+ project_watchers += User.where(id: user_ids, notification_level: Notification::N_WATCH)
+
+ project_watchers.uniq
+ end
+
+ # Remove users with disabled notifications from array
+ # Also remove duplications and nil recipients
+ def reject_muted_users(users, project = nil)
+ users = users.compact.uniq
+
+ users.reject do |user|
+ next user.notification.disabled? unless project
+
+ tm = project.users_projects.find_by_user_id(user.id)
+
+ # reject users who globally disabled notification and has no membership
+ next user.notification.disabled? unless tm
+
+ # reject users who disabled notification in project
+ next true if tm.notification.disabled?
+
+ # reject users who have N_GLOBAL in project and disabled in global settings
+ tm.notification.global? && user.notification.disabled?
+ end
+ end
+
+ def new_resource_email(target, method)
+ recipients = reject_muted_users([target.assignee], target.project)
+ recipients = recipients.concat(project_watchers(target.project)).uniq
+ recipients.delete(target.author)
+
+ recipients.each do |recipient|
+ mailer.send(method, recipient.id, target.id)
+ end
+ end
+
+ def close_resource_email(target, current_user, method)
+ recipients = reject_muted_users([target.author, target.assignee], target.project)
+ recipients = recipients.concat(project_watchers(target.project)).uniq
+ recipients.delete(current_user)
+
+ recipients.each do |recipient|
+ mailer.send(method, recipient.id, target.id, current_user.id)
+ end
+ end
+
+ def reassign_resource_email(target, current_user, method)
+ recipients = User.where(id: [target.assignee_id, target.assignee_id_was])
+
+ # Add watchers to email list
+ recipients = recipients.concat(project_watchers(target.project))
+
+ # reject users with disabled notifications
+ recipients = reject_muted_users(recipients, target.project)
+
+ # Reject me from recipients if I reassign an item
+ recipients.delete(current_user)
+
+ recipients.each do |recipient|
+ mailer.send(method, recipient.id, target.id, target.assignee_id_was)
+ end
+ end
+
+ def mailer
+ Notify.delay
+ end
+end
diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb
index 719e0d3db23..3b8c4847f20 100644
--- a/app/services/project_transfer_service.rb
+++ b/app/services/project_transfer_service.rb
@@ -5,6 +5,8 @@
class ProjectTransferService
include Gitlab::ShellAdapter
+ class TransferError < StandardError; end
+
attr_accessor :project
def transfer(project, new_namespace)
@@ -19,14 +21,16 @@ class ProjectTransferService
project.namespace = new_namespace
project.save!
+ # Move main repository
unless gitlab_shell.mv_repository(old_path, new_path)
raise TransferError.new('Cannot move project')
end
+ # Move wiki repo also if present
+ gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki")
+
true
end
- rescue => ex
- raise Project::TransferError.new(ex.message)
end
end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 132bb14a675..a52d13d5237 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -26,6 +26,7 @@ class SystemHooksService
data.merge!({
name: model.name,
path: model.path,
+ path_with_namespace: model.path_with_namespace,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email
diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb
index 200700b8810..c0afe9686f1 100644
--- a/app/uploaders/attachment_uploader.rb
+++ b/app/uploaders/attachment_uploader.rb
@@ -8,12 +8,12 @@ class AttachmentUploader < CarrierWave::Uploader::Base
end
def image?
- img_ext = %w(png jpg jpeg)
+ img_ext = %w(png jpg jpeg gif bmp tiff)
if file.respond_to?(:extension)
- img_ext.include?(file.extension)
+ img_ext.include?(file.extension.downcase)
else
# Not all CarrierWave storages respond to :extension
- ext = file.path.split('.').last
+ ext = file.path.split('.').last.downcase
img_ext.include?(ext)
end
rescue
@@ -21,10 +21,10 @@ class AttachmentUploader < CarrierWave::Uploader::Base
end
def secure_url
- if self.class.storage == CarrierWave::Storage::File
- "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}"
- else
- url
- end
+ "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}"
+ end
+
+ def file_storage?
+ self.class.storage == CarrierWave::Storage::File
end
end
diff --git a/app/views/admin/resque/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index 499738f9a06..499738f9a06 100644
--- a/app/views/admin/resque/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 46a876294ce..d3c938bb8f2 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -9,20 +9,20 @@
= link_to 'New Project', new_project_path, class: "btn btn-small"
.span4
.ui-box
- %h5.title Groups
- .data.padded
- = link_to admin_groups_path do
- %h1= Group.count
- %hr
- = link_to 'New Group', new_admin_group_path, class: "btn btn-small"
- .span4
- .ui-box
%h5.title Users
.data.padded
= link_to admin_users_path do
%h1= User.count
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-small"
+ .span4
+ .ui-box
+ %h5.title Groups
+ .data.padded
+ = link_to admin_groups_path do
+ %h1= Group.count
+ %hr
+ = link_to 'New Group', new_admin_group_path, class: "btn btn-small"
.row
.span4
diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml
index bb1398f66cd..af87503128e 100644
--- a/app/views/admin/groups/edit.html.haml
+++ b/app/views/admin/groups/edit.html.haml
@@ -27,5 +27,5 @@
%li It will change the git path to repositories under this group.
.form-actions
- = f.submit 'Edit group', class: "btn btn-remove"
+ = f.submit 'Save changes', class: "btn btn-primary"
= link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 0029cc78e3e..d880ff61c9b 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -1,5 +1,5 @@
%h3.page_title
- Groups
+ Groups (#{@groups.total_count})
%small
allows you to keep projects organized.
Use groups for uniting related projects.
@@ -7,31 +7,42 @@
= link_to 'New Group', new_admin_group_path, class: "btn btn-small pull-right"
%br
= form_tag admin_groups_path, method: :get, class: 'form-inline' do
- = text_field_tag :name, params[:name], class: "xlarge"
+ = text_field_tag :name, params[:name], class: "span6"
= submit_tag "Search", class: "btn submit btn-primary"
-%table
- %thead
- %tr
- %th
- Name
- %i.icon-sort-down
- %th Description
- %th Path
- %th Projects
- %th Owner
- %th.cred Danger Zone!
+%hr
+%ul.bordered-list
- @groups.each do |group|
- %tr
- %td
- %strong= link_to group.name, [:admin, group]
- %td= truncate group.description
- %td= group.path
- %td= group.projects.count
- %td
- = link_to group.owner_name, admin_user_path(group.owner)
- %td.bgred
- = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
- = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
-= paginate @groups, theme: "admin"
+ %li
+ .clearfix
+ .pull-right.prepend-top-10
+ = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
+ = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
+
+ %h4
+ = link_to [:admin, group] do
+ = group.name
+
+ &rarr;
+ %span.monospace
+ %i.icon-folder-close
+ %strong #{group.path}/
+
+ .clearfix.light.append-bottom-10
+ %span
+ %b Owner:
+ - if group.owner
+ = link_to group.owner_name, admin_user_path(group.owner)
+ - else
+ (deleted)
+ \|
+ %span
+ %b Projects:
+ %span.badge= group.projects.count
+
+ .clearfix
+ %p
+ = truncate group.description, length: 150
+
+= paginate @groups, theme: "gitlab"
diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml
index 3fa63e1ba25..2da654ec764 100644
--- a/app/views/admin/groups/new.html.haml
+++ b/app/views/admin/groups/new.html.haml
@@ -15,7 +15,7 @@
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
- = f.submit 'Create group', class: "btn btn-primary"
+ = f.submit 'Create group', class: "btn btn-create"
%hr
.padded
@@ -23,5 +23,5 @@
%li Group is kind of directory for several projects
%li All created groups are private
%li People within a group see only projects they have access to
- %li All projects of group will be stored in group directory
+ %li All projects of group will be stored in a group directory
%li You will be able to move existing projects into group
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 63ea78fdd99..0e2e144d326 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -94,7 +94,7 @@
%td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"}
%tr
- %td= submit_tag 'Add user to projects in group', class: "btn btn-primary"
+ %td= submit_tag 'Add user to projects in group', class: "btn btn-create"
%td
Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
@@ -116,18 +116,5 @@
.input
= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
.form-actions
- = submit_tag 'Add', class: "btn btn-primary"
-
-:javascript
- $(function(){
- var modal = $('.change-owner-holder');
- $('.change-owner-link').bind("click", function(){
- $(this).hide();
- modal.show();
- });
- $('.change-owner-cancel-link').bind("click", function(){
- modal.hide();
- $('.change-owner-link').show();
- })
- })
+ = submit_tag 'Move projects', class: "btn btn-create"
diff --git a/app/views/admin/hooks/_data_ex.html.erb b/app/views/admin/hooks/_data_ex.html.erb
index 652ee5aa56f..eeb78b5f0c5 100644
--- a/app/views/admin/hooks/_data_ex.html.erb
+++ b/app/views/admin/hooks/_data_ex.html.erb
@@ -28,8 +28,8 @@
"project_id": 74,
"project_name": "StoreCloud",
"project_path": "storecloud",
- "owner_email": "johnsmith@gmail.com",
- "owner_name": "John Smith",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
}
4. Team Member Removed:
@@ -40,8 +40,8 @@
"project_id": 74,
"project_name": "StoreCloud",
"project_path": "storecloud",
- "owner_email": "johnsmith@gmail.com",
- "owner_name": "John Smith",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
}
5. User created:
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index acbf7a108b8..316e8235cbe 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -15,7 +15,7 @@
.input
= f.text_field :url, class: "text_field xxlarge"
&nbsp;
- = f.submit "Add System Hook", class: "btn btn-primary"
+ = f.submit "Add System Hook", class: "btn btn-create"
%hr
-if @hooks.any?
diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml
deleted file mode 100644
index 29b90bdd4cb..00000000000
--- a/app/views/admin/projects/_form.html.haml
+++ /dev/null
@@ -1,86 +0,0 @@
-= form_for [:admin, project] do |f|
- -if project.errors.any?
- .alert.alert-error
- %ul
- - project.errors.full_messages.each do |msg|
- %li= msg
-
- .clearfix.project_name_holder
- = f.label :name do
- Project name is
- .input
- = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
-
- - if project.repo_exists?
- %fieldset.adv_settings
- %legend Advanced settings:
- .clearfix
- = f.label :path do
- Path
- .input
- = text_field_tag :ppath, @project.repository.path_to_repo, class: "xlarge", disabled: true
-
- .clearfix
- = f.label :default_branch, "Default Branch"
- .input= f.select(:default_branch, @project.repository.heads.map(&:name), {}, style: "width:210px;")
-
- %fieldset.adv_settings
- %legend Features:
-
- .clearfix
- = f.label :issues_enabled, "Issues"
- .input= f.check_box :issues_enabled
-
- - if Project.issues_tracker.values.count > 1
- .clearfix
- = f.label :issues_tracker, "Issues tracker", class: 'control-label'
- .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
-
- .clearfix
- = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
- .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
-
- .clearfix
- = f.label :merge_requests_enabled, "Merge Requests"
- .input= f.check_box :merge_requests_enabled
-
- .clearfix
- = f.label :wall_enabled, "Wall"
- .input= f.check_box :wall_enabled
-
- .clearfix
- = f.label :wiki_enabled, "Wiki"
- .input= f.check_box :wiki_enabled
-
- %fieldset.features
- %legend Public mode:
- .clearfix
- = f.label :public do
- %span Allow public http clone
- .input= f.check_box :public
-
- %fieldset.features
- %legend Transfer:
- .control-group
- = f.label :namespace_id do
- %span Namespace
- .controls
- = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
- %br
- %ul.prepend-top-10.cred
- %li Be careful. Changing project namespace can have unintended side effects
- %li You can transfer project only to namespaces you can manage
- %li You will need to update your local repositories to point to the new location.
-
-
- .actions
- = f.submit 'Save Project', class: "btn btn-save"
- = link_to 'Cancel', admin_projects_path, class: "btn btn-cancel"
-
-
-
-:javascript
- $(function(){
- new Projects();
- })
-
diff --git a/app/views/admin/projects/edit.html.haml b/app/views/admin/projects/edit.html.haml
deleted file mode 100644
index 7b59a0cc753..00000000000
--- a/app/views/admin/projects/edit.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-%h3.page_title #{@project.name} &rarr; Edit project
-%hr
-= render 'form', project: @project
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 15b2778252a..59831d83cc2 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -52,10 +52,8 @@
%i.icon-lock.cgreen
= link_to project.name_with_namespace, [:admin, project]
.pull-right
- = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
+ = link_to 'Destroy', [project], confirm: remove_project_message(project), method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
%p.nothing_here_message 0 projects matches
- - else
- %li.bottom
- = paginate @projects, theme: "gitlab"
+ = paginate @projects, theme: "gitlab"
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 65b921170fd..92b8960151e 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -1,129 +1,90 @@
%h3.page_title
Project: #{@project.name_with_namespace}
- = link_to edit_admin_project_path(@project), class: "btn pull-right" do
+ = link_to edit_project_path(@project), class: "btn pull-right" do
%i.icon-edit
Edit
+%hr
+.row
+ .span6
+ .ui-box
+ %h5.title
+ Project info:
+ %ul.well-list
+ %li
+ %span.light Name:
+ %strong= @project.name
+ %li
+ %span.light Namespace:
+ %strong
+ - if @project.namespace
+ = link_to @project.namespace.human_name, [:admin, @project.group || @project.owner]
+ - else
+ Global
+ %li
+ %span.light Owned by:
+ %strong
+ - if @project.owner
+ = link_to @project.owner_name, admin_user_path(@project.owner)
+ - else
+ (deleted)
+ %li
+ %span.light Created by:
+ %strong
+ = @project.creator.try(:name) || '(deleted)'
-%br
-%table.zebra-striped
- %thead
- %tr
- %th Project
- %th
- %tr
- %td
- %b
- Name:
- %td
- = @project.name
- %tr
- %td
- %b
- Namespace:
- %td
- - if @project.namespace
- = @project.namespace.human_name
- - else
- Global
- %tr
- %td
- %b
- Owned by:
- %td
- - if @project.owner
- = link_to @project.owner_name, admin_user_path(@project.owner)
- - else
- (deleted)
- %tr
- %td
- %b
- Created by:
- %td
- = @project.creator.try(:name) || '(deleted)'
- %tr
- %td
- %b
- Created at:
- %td
- = @project.created_at.stamp("March 1, 1999")
- %tr
- %td
- %b
- Smart HTTP:
- %td
- = link_to @project.http_url_to_repo
- %tr
- %td
- %b
- SSH:
- %td
- = link_to @project.ssh_url_to_repo
- - if @project.public
- %tr.bgred
- %td
- %b
- Public Read-Only Code access:
- %td
- = check_box_tag 'public', nil, @project.public
+ %li
+ %span.light Created at:
+ %strong
+ = @project.created_at.stamp("March 1, 1999")
-- if @repository
- %table.zebra-striped
- %thead
- %tr
- %th Repository
- %th
- %tr
- %td
- %b
- FS Path:
- %td
- %code= @repository.path_to_repo
- %tr
- %td
- %b
- Last commit at:
- %td
- = last_commit(@project)
+ %li
+ %span.light http:
+ %strong
+ = link_to @project.http_url_to_repo
+ %li
+ %span.light ssh:
+ %strong
+ = link_to @project.ssh_url_to_repo
+ - if @project.repository.exists?
+ %li
+ %span.light fs:
+ %strong
+ = @repository.path_to_repo
-%br
-%h5
- Team
- %small
- (#{@project.users.count})
-%br
-%table.zebra-striped.team_members
- %thead
- %tr
- %th Name
- %th Project Access
- %th Repository Access
- %th
+ %li
+ %span.light last commit:
+ %strong
+ = last_commit(@project)
+ - else
+ %li
+ %span.light repository:
+ %strong.cred
+ does not exist
- - @project.users.each do |tm|
- %tr
- %td
- = link_to tm.name, admin_user_path(tm)
- %td= @project.project_access_human(tm)
- %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn btn-small"
- %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove small"
-
-%br
-%h5 Add new team member
-%br
-= form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do
- %table.zebra-striped
- %thead
- %tr
- %th Users
- %th Project Access:
-
- %tr
- %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5'
- %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"}
-
- %tr
- %td= submit_tag 'Add', class: "btn btn-primary"
- %td
- Read more about project permissions
- %strong= link_to "here", help_permissions_path, class: "vlink"
+ %li
+ %span.light access:
+ %strong
+ - if @project.public
+ %span.cblue
+ %i.icon-share
+ Public
+ - else
+ %span.cgreen
+ %i.icon-lock
+ Private
+ .span6
+ .ui-box
+ %h5.title
+ Team
+ %small
+ (#{@project.users.count})
+ = link_to project_team_index_path(@project), class: "btn btn-tiny" do
+ %i.icon-edit
+ Edit Team
+ %ul.well-list.team_members
+ - @project.users.each do |tm|
+ %li
+ %strong
+ = link_to tm.name, admin_user_path(tm)
+ %span.pull-right.light= @project.project_access_human(tm)
diff --git a/app/views/admin/projects/team.html.haml b/app/views/admin/projects/team.html.haml
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/views/admin/projects/team.html.haml
+++ /dev/null
diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml
index 3690d6d9eb4..cf24ed5398f 100644
--- a/app/views/admin/teams/index.html.haml
+++ b/app/views/admin/teams/index.html.haml
@@ -1,7 +1,7 @@
%h3.page_title
Teams
%small
- simple Teams description
+ allow you to organize groups of people that have a common focus. Use teams to simplify the process of assigning roles to groups of people.
= link_to 'New Team', new_admin_team_path, class: "btn btn-small pull-right"
%br
@@ -40,4 +40,4 @@
= link_to 'Edit', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small"
= link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
-= paginate @teams, theme: "admin"
+= paginate @teams, theme: "gitlab"
diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml
index 1c90cb20c10..8bccdacc351 100644
--- a/app/views/admin/teams/new.html.haml
+++ b/app/views/admin/teams/new.html.haml
@@ -16,7 +16,7 @@
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
- = f.submit 'Create team', class: "btn btn-primary"
+ = f.submit 'Create team', class: "btn btn-create"
%hr
.padded
diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml
index abdfada8c5e..bd4d90b607f 100644
--- a/app/views/admin/teams/show.html.haml
+++ b/app/views/admin/teams/show.html.haml
@@ -91,17 +91,3 @@
= link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn btn-small"
&nbsp;
= link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "relegate_project_#{project.id}"
-
-:javascript
- $(function(){
- var modal = $('.change-owner-holder');
- $('.change-owner-link').bind("click", function(){
- $(this).hide();
- modal.show();
- });
- $('.change-owner-cancel-link').bind("click", function(){
- modal.hide();
- $('.change-owner-link').show();
- })
- })
-
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 1d1fe341c5b..9bde50f8947 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -80,8 +80,9 @@
.input= f.text_field :twitter
.actions
- = f.submit 'Save', class: "btn btn-save"
- if @admin_user.new_record?
+ = f.submit 'Create user', class: "btn btn-create"
= link_to 'Cancel', admin_users_path, class: "btn btn-cancel"
- else
+ = f.submit 'Save changes', class: "btn btn-save"
= link_to 'Cancel', admin_user_path(@admin_user), class: "btn btn-cancel"
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 9da2871e992..3657f660c9b 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -58,5 +58,4 @@
- else
= link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove"
= link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove"
- %li.bottom
- = paginate @admin_users, theme: "gitlab"
+ = paginate @admin_users, theme: "gitlab"
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index b813f859a0b..6709b8f8a6b 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -71,7 +71,7 @@
.ui-box
%h5.title Projects (#{@projects.count})
%ul.well-list
- - @projects.each do |project|
+ - @projects.sort_by(&:name_with_namespace).each do |project|
%li
= link_to admin_project_path(project), class: dom_class(project) do
- if project.namespace
@@ -87,7 +87,7 @@
= tm.project_access_human
= link_to edit_admin_project_member_path(project, tm.user), class: "btn btn-small" do
%i.icon-edit
- = link_to admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove" do
+ = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @admin_user), method: :delete, class: "btn btn-small btn-remove" do
%i.icon-remove
%p.light
%i.icon-wrench
diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml
index b2a45ef5303..297e30356a7 100644
--- a/app/views/blame/show.html.haml
+++ b/app/views/blame/show.html.haml
@@ -6,7 +6,7 @@
%i.icon-angle-right
= link_to project_tree_path(@project, @ref) do
= @project.name
- - @tree.breadcrumbs(6) do |link|
+ - tree_breadcrumbs(@tree, 6) do |link|
\/
%li= link
.clear
@@ -15,20 +15,20 @@
.file_title
%i.icon-file
%span.file_name
- = @tree.name
- %small= number_to_human_size @tree.size
- %span.options= render "tree/blob_actions"
+ = @blob.name
+ %small= number_to_human_size @blob.size
+ %span.options= render "blob/actions"
.file_content.blame
%table
- current_line = 1
- @blame.each do |commit, lines|
- - commit = CommitDecorator.decorate(Commit.new(commit))
+ - commit = Commit.new(commit)
%tr
%td.blame-commit
%span.commit
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
&nbsp;
- = commit.author_link avatar: true, size: 16
+ = commit_author_link(commit, avatar: true, size: 16)
&nbsp;
= link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title"
%td.lines.blame-numbers
@@ -43,6 +43,7 @@
- current_line += 1
%td.lines
%pre
- - lines.each do |line|
- = line
- \
+ :erb
+ <% lines.each do |line| %>
+ <%= line %>
+ <% end %>
diff --git a/app/views/tree/_blob_actions.html.haml b/app/views/blob/_actions.html.haml
index 0bde968d0e6..456c7432c94 100644
--- a/app/views/tree/_blob_actions.html.haml
+++ b/app/views/blob/_actions.html.haml
@@ -1,12 +1,12 @@
.btn-group.tree-btn-group
-# only show edit link for text files
- - if @tree.text?
- = link_to "edit", edit_project_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit?
- = link_to "raw", project_blob_path(@project, @id), class: "btn btn-tiny", target: "_blank"
+ - if @blob.text?
+ = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit?
+ = link_to "raw", project_raw_path(@project, @id), class: "btn btn-tiny", target: "_blank"
-# only show normal/blame view links for text files
- - if @tree.text?
+ - if @blob.text?
- if current_page? project_blame_path(@project, @id)
- = link_to "normal view", project_tree_path(@project, @id), class: "btn btn-tiny"
+ = link_to "normal view", project_blob_path(@project, @id), class: "btn btn-tiny"
- else
- = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny"
+ = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" unless @blob.empty?
= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny"
diff --git a/app/views/blob/_blob.html.haml b/app/views/blob/_blob.html.haml
new file mode 100644
index 00000000000..68d6c06065c
--- /dev/null
+++ b/app/views/blob/_blob.html.haml
@@ -0,0 +1,32 @@
+%ul.breadcrumb
+ %li
+ %i.icon-angle-right
+ = link_to project_tree_path(@project, @ref) do
+ = @project.path
+ - tree_breadcrumbs(@tree, 6) do |title, path|
+ \/
+ %li
+ - if path
+ - if path.end_with?(@path)
+ = link_to project_blob_path(@project, path) do
+ %span.cblue
+ = truncate(title, length: 40)
+ - else
+ = link_to truncate(title, length: 40), project_tree_path(@project, path)
+ - else
+ = link_to title, '#'
+
+%div#tree-content-holder.tree-content-holder
+ .file_holder
+ .file_title
+ %i.icon-file
+ %span.file_name
+ = blob.name
+ %small= number_to_human_size blob.size
+ %span.options= render "actions"
+ - if blob.text?
+ = render "text", blob: blob
+ - elsif blob.image?
+ = render "image", blob: blob
+ - else
+ = render "download", blob: blob
diff --git a/app/views/tree/blob/_download.html.haml b/app/views/blob/_download.html.haml
index 864c209db76..864c209db76 100644
--- a/app/views/tree/blob/_download.html.haml
+++ b/app/views/blob/_download.html.haml
diff --git a/app/views/tree/blob/_image.html.haml b/app/views/blob/_image.html.haml
index 7b23f0c810c..7b23f0c810c 100644
--- a/app/views/tree/blob/_image.html.haml
+++ b/app/views/blob/_image.html.haml
diff --git a/app/views/tree/blob/_text.html.haml b/app/views/blob/_text.html.haml
index 122e275219d..122e275219d 100644
--- a/app/views/tree/blob/_text.html.haml
+++ b/app/views/blob/_text.html.haml
diff --git a/app/views/blob/show.html.haml b/app/views/blob/show.html.haml
new file mode 100644
index 00000000000..d96595bc7f0
--- /dev/null
+++ b/app/views/blob/show.html.haml
@@ -0,0 +1,4 @@
+%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/commit/_commit_box.html.haml b/app/views/commit/_commit_box.html.haml
index 4c80c13ced1..646791773b2 100644
--- a/app/views/commit/_commit_box.html.haml
+++ b/app/views/commit/_commit_box.html.haml
@@ -24,14 +24,14 @@
.row
.span5
.author
- = @commit.author_link avatar: true, size: 32
+ = commit_author_link(@commit, avatar: true, size: 32)
authored
%time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.authored_date)} ago
- if @commit.different_committer?
.committer
&rarr;
- = @commit.committer_link
+ = commit_committer_link(@commit)
committed
%time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
#{time_ago_in_words(@commit.committed_date)} ago
diff --git a/app/views/commit/huge_commit.html.haml b/app/views/commit/huge_commit.html.haml
index 7f0bcf38037..5d447d6cee5 100644
--- a/app/views/commit/huge_commit.html.haml
+++ b/app/views/commit/huge_commit.html.haml
@@ -1,3 +1,3 @@
-= render "commits/commit_box"
+= render "commit/commit_box"
.alert.alert-error
%h4 Commit diffs are too big to be displayed
diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml
index 48fb44a99d5..6cb1a6905ca 100644
--- a/app/views/commit/show.html.haml
+++ b/app/views/commit/show.html.haml
@@ -9,10 +9,3 @@
= render "commits/diffs", diffs: @commit.diffs
= render "notes/notes_with_form"
-
-:javascript
- $(function(){
- $('.files .file').each(function(){
- new CommitFile(this);
- });
- });
diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml
index 2f5ff130f03..eba6c206c46 100644
--- a/app/views/commits/_commit.html.haml
+++ b/app/views/commits/_commit.html.haml
@@ -4,7 +4,7 @@
%strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
%p
= link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
- = commit.author_link avatar: true, size: 24
+ = commit_author_link(commit, avatar: true, size: 24)
&nbsp;
= link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title"
@@ -16,6 +16,6 @@
%span.notes_count
- notes = @project.notes.for_commit_id(commit.id)
- if notes.any?
- %span.btn.disabled.grouped
+ %span.badge.badge-info
%i.icon-comment
= notes.count
diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml
index 869d1f9c769..933780e4534 100644
--- a/app/views/commits/_commits.html.haml
+++ b/app/views/commits/_commits.html.haml
@@ -3,4 +3,7 @@
%h5.title
%i.icon-calendar
%span= day.stamp("28 Aug, 2010")
+
+ .pull-right
+ %small= pluralize(commits.count, 'commit')
%ul.well-list= render commits
diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml
index b2da4796db6..3f4d51f753a 100644
--- a/app/views/commits/_diffs.html.haml
+++ b/app/views/commits/_diffs.html.haml
@@ -16,16 +16,16 @@
- unless @suppress_diff
- diffs.each_with_index do |diff, i|
- next if diff.diff.empty?
- - file = (@commit.tree / diff.new_path)
- - file = (@commit.prev_commit.tree / diff.old_path) unless file
- - next unless file
+ - file = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, diff.new_path)
+ - file = Gitlab::Git::Blob.new(@repository, @commit.parent_id, @ref, diff.old_path) unless file.exists?
+ - next unless file.exists?
.file{id: "diff-#{i}"}
.header
- if diff.deleted_file
%span= diff.old_path
- - if @commit.prev_commit
- = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do
+ - if @commit.parent_ids.present?
+ = link_to project_blob_path(@project, tree_join(@commit.parent_id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do
View file @
%span.commit-short-id= @commit.short_id(6)
- else
@@ -33,7 +33,7 @@
- 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_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do
+ = link_to project_blob_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do
View file @
%span.commit-short-id= @commit.short_id(6)
@@ -43,7 +43,7 @@
- if file.text?
= render "commits/text_file", diff: diff, index: i
- elsif file.image?
- - old_file = (@commit.prev_commit.tree / diff.old_path) if !@commit.prev_commit.nil?
+ - old_file = Gitlab::Git::Blob.new(@repository, @commit.parent_id, @ref, diff.old_path) if @commit.parent_id
= render "commits/image", diff: diff, old_file: old_file, file: file, index: i
- else
%p.nothing_here_message No preview for this file type
diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml
index 760fd07ed8b..8f737e43887 100644
--- a/app/views/commits/_text_file.html.haml
+++ b/app/views/commits/_text_file.html.haml
@@ -4,7 +4,7 @@
%table.text-file{class: "#{'hide' if too_big}"}
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old|
- %tr.line_holder{ id: line_code }
+ %tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
%td.old_line= "..."
%td.new_line= "..."
diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml
index d180b8ec426..cb9ef820d3e 100644
--- a/app/views/commits/show.html.haml
+++ b/app/views/commits/show.html.haml
@@ -2,7 +2,7 @@
- if @path.present?
%ul.breadcrumb
- = breadcrumbs
+ = commits_breadcrumbs
%div{id: dom_id(@project)}
#commits-list= render "commits"
@@ -11,7 +11,5 @@
- if @commits.count == @limit
:javascript
- $(function(){
- CommitsList.init("#{@ref}", #{@limit});
- });
+ CommitsList.init("#{@ref}", #{@limit});
diff --git a/app/views/compare/show.html.haml b/app/views/compare/show.html.haml
index 476be2550af..56c4a113ea0 100644
--- a/app/views/compare/show.html.haml
+++ b/app/views/compare/show.html.haml
@@ -16,7 +16,7 @@
%div.ui-box
%h5.title
Commits (#{@commits.count})
- %ul.well-list= render @commits
+ %ul.well-list= render Commit.decorate(@commits)
- unless @diffs.empty?
%h4 Diff
diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml
index 3124d76aa7f..2fedf87a9ba 100644
--- a/app/views/dashboard/_groups.html.haml
+++ b/app/views/dashboard/_groups.html.haml
@@ -1,11 +1,11 @@
.ui-box
%h5.title
Groups
- %small
+ %span.light
(#{groups.count})
- if current_user.can_create_group?
%span.pull-right
- = link_to new_group_path, class: "btn btn-tiny info" do
+ = link_to new_group_path, class: "btn btn-small" do
%i.icon-plus
New Group
%ul.well-list
diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml
index 105e23fe12a..a106e83e783 100644
--- a/app/views/dashboard/_projects.html.haml
+++ b/app/views/dashboard/_projects.html.haml
@@ -1,11 +1,11 @@
.ui-box
%h5.title
Projects
- %small
+ %span.light
(#{@projects_count})
- if current_user.can_create_project?
%span.pull-right
- = link_to new_project_path, class: "btn btn-tiny info" do
+ = link_to new_project_path, class: "btn btn-small" do
%i.icon-plus
New Project
diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml
index 876a5b61297..748ff9810b5 100644
--- a/app/views/dashboard/_sidebar.html.haml
+++ b/app/views/dashboard/_sidebar.html.haml
@@ -22,7 +22,4 @@
News Feed
%hr
-.gitlab-promo
- = link_to "Homepage", "http://gitlab.org"
- = link_to "Blog", "http://blog.gitlab.org"
- = link_to "@gitlabhq", "https://twitter.com/gitlabhq"
+= render 'shared/promo'
diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml
index 5c28f964cb6..95d87f508e0 100644
--- a/app/views/dashboard/_teams.html.haml
+++ b/app/views/dashboard/_teams.html.haml
@@ -1,10 +1,10 @@
.ui-box.teams-box
%h5.title
Teams
- %small
+ %span.light
(#{teams.count})
%span.pull-right
- = link_to new_team_path, class: "btn btn-tiny info" do
+ = link_to new_team_path, class: "btn btn-small" do
%i.icon-plus
New Team
%ul.well-list
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 539c57651f7..b41edb9eb60 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -15,7 +15,12 @@
- project = group[0]
%h5.title
= link_to_project project
- %ul.well-list.issues_table
+ &nbsp;
+ %i.icon-angle-right
+ &nbsp;
+ = link_to 'issues', project_issues_path(project)
+
+ %ul.well-list.issues-list
- group[1].each do |issue|
= render issue
%hr
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
index 29a16d61e63..9b16db340b2 100644
--- a/app/views/dashboard/projects.html.haml
+++ b/app/views/dashboard/projects.html.haml
@@ -20,6 +20,15 @@
= nav_tab :scope, 'joined' do
= link_to "Joined", projects_dashboard_path(scope: 'joined')
+ %p.light Filter by label:
+ %ul.bordered-list
+ - @labels.each do |label|
+ %li{ class: (label.name == params[:label]) ? 'active' : 'light' }
+ = link_to projects_dashboard_path(scope: params[:scope], label: label.name) do
+ %i.icon-tag
+ = label.name
+
+
.span9
= form_tag projects_dashboard_path, method: 'get' do
%fieldset.dashboard-search-filter
@@ -28,7 +37,7 @@
= button_tag type: 'submit', class: 'btn' do
%i.icon-search
- %ul.well-list
+ %ul.bordered-list
- @projects.each do |project|
%li.clearfix
.clearfix
@@ -36,7 +45,7 @@
= link_to project_path(project), class: dom_class(project) do
- if project.namespace
= project.namespace.human_name
- \/
+ %span= "/"
%strong
= truncate(project.name, length: 45)
.pull-right.light
@@ -49,6 +58,10 @@
.left
- if project.description.present?
%span.light= project.description
+ - project.labels.each do |label|
+ %span.label.label-info
+ %i.icon-tag
+ = label.name
.pull-right.light
%small.light
diff --git a/app/views/dashboard/show.atom.builder b/app/views/dashboard/show.atom.builder
index 29b2e4a26d8..a913df92299 100644
--- a/app/views/dashboard/show.atom.builder
+++ b/app/views/dashboard/show.atom.builder
@@ -8,11 +8,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
@events.each do |event|
if event.proper?
- event = EventDecorator.decorate(event)
xml.entry do
- event_link = event.feed_url
- event_title = event.feed_title
- event_summary = event.feed_summary
+ event_link = event_feed_url(event)
+ event_title = event_feed_title(event)
+ event_summary = event_feed_summary(event)
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link :href => event_link
diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml
index 1a66ba4fb37..2305eae1f71 100644
--- a/app/views/dashboard/show.html.haml
+++ b/app/views/dashboard/show.html.haml
@@ -1,5 +1,5 @@
- if @has_authorized_projects
- .projects
+ .dashboard
.activities.span8
= render 'activities'
.side.span4
@@ -7,6 +7,3 @@
- else
= render "zero_authorized_projects"
-
-:javascript
- dashboardPage();
diff --git a/app/views/deploy_keys/_deploy_key.html.haml b/app/views/deploy_keys/_deploy_key.html.haml
new file mode 100644
index 00000000000..45f80ecd556
--- /dev/null
+++ b/app/views/deploy_keys/_deploy_key.html.haml
@@ -0,0 +1,25 @@
+%li
+ .pull-right
+ - if @available_keys.include?(deploy_key)
+ = link_to enable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
+ %i.icon-plus
+ Enable
+ - else
+ - if deploy_key.projects.count > 1
+ = link_to disable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
+ %i.icon-off
+ Disable
+ - else
+ = link_to 'Remove', project_deploy_key_path(@project, deploy_key), confirm: 'You are going to remove deploy key. Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
+
+
+ = link_to project_deploy_key_path(deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first, deploy_key) do
+ %i.icon-key
+ %strong= deploy_key.title
+
+ %p.light.prepend-top-10
+ - deploy_key.projects.map(&:name_with_namespace).each do |project_name|
+ %span.label= project_name
+ %small.pull-right
+ Created #{time_ago_in_words(deploy_key.created_at)} ago
+
diff --git a/app/views/deploy_keys/_form.html.haml b/app/views/deploy_keys/_form.html.haml
index 5fb83021dc0..71bf309dd8b 100644
--- a/app/views/deploy_keys/_form.html.haml
+++ b/app/views/deploy_keys/_form.html.haml
@@ -18,6 +18,6 @@
= link_to "here", help_ssh_path
.actions
- = f.submit 'Save', class: "btn-save btn"
+ = f.submit 'Create', class: "btn-create btn"
= link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel"
diff --git a/app/views/deploy_keys/_show.html.haml b/app/views/deploy_keys/_show.html.haml
deleted file mode 100644
index 635054350ec..00000000000
--- a/app/views/deploy_keys/_show.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-%tr
- %td
- %a{href: project_deploy_key_path(key.project, key)}
- %strong= key.title
- %td
- %span.update-author
- Added
- = time_ago_in_words(key.created_at)
- ago
- %td
- = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
-
diff --git a/app/views/deploy_keys/index.html.haml b/app/views/deploy_keys/index.html.haml
index 80d30e1c2dc..7801302d3f4 100644
--- a/app/views/deploy_keys/index.html.haml
+++ b/app/views/deploy_keys/index.html.haml
@@ -1,17 +1,32 @@
= render "projects/settings_nav"
%p.slead
- Deploy keys allow read-only access to repository. It matches perfectly for CI, staging or production servers.
+ Deploy keys allow read-only access to repository. They can be used for CI, staging or production servers
- - if can? current_user, :admin_project, @project
- = link_to new_project_deploy_key_path(@project), class: "btn btn-small", title: "New Deploy Key" do
- Add Deploy Key
-- if @keys.any?
- %table
- %thead
- %tr
- %th Keys
- %th
- %th
- - @keys.each do |key|
- = render(partial: 'show', locals: {key: key})
+%p
+ You can create a deploy key or add existing one
+ = link_to new_project_deploy_key_path(@project), class: "btn btn-primary pull-right", title: "New Deploy Key" do
+ %i.icon-plus
+ New Deploy Key
+
+%hr.clearfix
+
+.row
+ .span6.enabled-keys
+ %h5.cgreen
+ Enabled deploy keys
+ %small for this project
+ %ul.bordered-list
+ = render @enabled_keys
+ - if @enabled_keys.blank?
+ .light-well
+ %p.nothing_here_message Create #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add existing one
+ .span6.available-keys
+ %h5
+ Available deploy keys
+ %small from projects you are able to manage
+ %ul.bordered-list
+ = render @available_keys
+ - if @available_keys.blank?
+ .light-well
+ %p.nothing_here_message All deploy keys created in projects you own will be displayed here
diff --git a/app/views/deploy_keys/show.html.haml b/app/views/deploy_keys/show.html.haml
index 0a9f376d046..5b59d322343 100644
--- a/app/views/deploy_keys/show.html.haml
+++ b/app/views/deploy_keys/show.html.haml
@@ -12,4 +12,4 @@
%hr
%pre= @key.key
.pull-right
- = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key"
+ = link_to 'Remove', project_deploy_key_path(@project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key"
diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb
index 5399a961570..adc9b672092 100644
--- a/app/views/devise/confirmations/new.html.erb
+++ b/app/views/devise/confirmations/new.html.erb
@@ -1,6 +1,6 @@
<h2>Resend confirmation instructions</h2>
-<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
+<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
@@ -9,4 +9,4 @@
<div><%= f.submit "Resend confirmation instructions" %></div>
<% end %>
-<%= render :partial => "devise/shared/links" %>
+<%= render partial: "devise/shared/links" %>
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb
index a6ea8ca17e8..7b4fd526964 100644
--- a/app/views/devise/mailer/confirmation_instructions.html.erb
+++ b/app/views/devise/mailer/confirmation_instructions.html.erb
@@ -2,4 +2,4 @@
<p>You can confirm your account through the link below:</p>
-<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>
+<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @resource.confirmation_token) %></p>
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb
index ae9e888abb9..e1144e943b4 100644
--- a/app/views/devise/mailer/reset_password_instructions.html.erb
+++ b/app/views/devise/mailer/reset_password_instructions.html.erb
@@ -2,7 +2,7 @@
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
-<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
+<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @resource.reset_password_token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb
index 2263c219522..0429883f05b 100644
--- a/app/views/devise/mailer/unlock_instructions.html.erb
+++ b/app/views/devise/mailer/unlock_instructions.html.erb
@@ -4,4 +4,4 @@
<p>Click the link below to unlock your account:</p>
-<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>
+<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @resource.unlock_token) %></p>
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
index dd26e8a47b8..139acf28a9f 100644
--- a/app/views/devise/registrations/edit.html.erb
+++ b/app/views/devise/registrations/edit.html.erb
@@ -1,6 +1,6 @@
<h2>Edit <%= resource_name.to_s.humanize %></h2>
-<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
+<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
@@ -18,11 +18,11 @@
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
-<div><%= f.submit "Update", :class => "input_button" %></div>
+<div><%= f.submit "Update", class: "input_button" %></div>
<% end %>
<h3>Cancel my account</h3>
-<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
+<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), confirm: "Are you sure?", method: :delete %>.</p>
<%= link_to "Back", :back %>
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
new file mode 100644
index 00000000000..1ca43d5dd08
--- /dev/null
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -0,0 +1,13 @@
+= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
+ = f.text_field :login, class: "text top", placeholder: "Username or Email", autofocus: "autofocus"
+ = f.password_field :password, class: "text bottom", placeholder: "Password"
+ - if devise_mapping.rememberable?
+ .clearfix.inputs-list
+ %label.checkbox.remember_me{for: "user_remember_me"}
+ = f.check_box :remember_me
+ %span Remember me
+ = f.submit "Sign in", class: "btn-create btn"
+ .pull-right
+ = link_to "Forgot your password?", new_password_path(resource_name), class: "btn"
+
+
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index eb8c5194607..575d33949b6 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -1,29 +1,5 @@
-= form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do
- = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo"
- = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login", :autofocus => "autofocus"}
- = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"}
+= form_tag(user_omniauth_callback_path(:ldap), id: 'new_ldap_user' ) do
+ = text_field_tag :username, nil, {class: "text top", placeholder: "LDAP Login", autofocus: "autofocus"}
+ = password_field_tag :password, nil, {class: "text bottom", placeholder: "Password"}
%br/
- = submit_tag "LDAP Sign in", :class => "btn-primary btn"
- - if devise_mapping.omniauthable?
- - (resource_class.omniauth_providers - [:ldap]).each do |provider|
- %hr/
- = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn btn-primary"
- %br/
- %hr/
- %a#other_form_toggle{:href => "#", :onclick => "javascript:$('#new_user').toggle();"} Other Sign in
- :javascript
- $(function() {
- $('#new_user').toggle();
- });
-= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f|
- = f.text_field :email, :class => "text top", :placeholder => "Email"
- = f.password_field :password, :class => "text bottom", :placeholder => "Password"
- - if devise_mapping.rememberable?
- .clearfix.inputs-list
- %label.checkbox.remember_me{:for => "user_remember_me"}
- = f.check_box :remember_me
- %span Remember me
- %br/
- = f.submit "Sign in", :class => "btn-primary btn"
- .pull-right
- = render :partial => "devise/shared/links"
+ = submit_tag "LDAP Sign in", class: "btn-create btn"
diff --git a/app/views/devise/sessions/_oauth_providers.html.haml b/app/views/devise/sessions/_oauth_providers.html.haml
new file mode 100644
index 00000000000..710a5d52514
--- /dev/null
+++ b/app/views/devise/sessions/_oauth_providers.html.haml
@@ -0,0 +1,10 @@
+- if enabled_oauth_providers.present?
+ %hr
+ %div{:'data-no-turbolink' => 'data-no-turbolink'}
+ %span Sign in with: &nbsp;
+ - (enabled_oauth_providers - [:ldap]).each do |provider|
+ %span
+ - if default_providers.include?(provider)
+ = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
+ - else
+ = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index d904e701b8a..8b71ebed5f4 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,28 +1,31 @@
-- if ldap_enable?
- = render :partial => 'devise/sessions/new_ldap'
-- else
- = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f|
- = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo"
- = f.email_field :email, :class => "text top", :placeholder => "Email", :autofocus => "autofocus"
- = f.password_field :password, :class => "text bottom", :placeholder => "Password"
- - if devise_mapping.rememberable?
- .clearfix.inputs-list
- %label.checkbox.remember_me{:for => "user_remember_me"}
- = f.check_box :remember_me
- %span Remember me
- %br/
- = f.submit "Sign in", :class => "btn-create btn"
- .pull-right
- = link_to "Forgot your password?", new_password_path(resource_name), :class => "btn"
- %br/
- - if Gitlab.config.gitlab.signup_enabled
- %hr/
+.login-box
+ = image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo"
+
+ - if ldap_enabled?
+ %ul.nav.nav-tabs
+ %li.active
+ = link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
+ %li
+ = link_to 'Ordinary', '#tab-signin', 'data-toggle' => 'tab'
+ .tab-content
+ %div#tab-ldap.tab-pane.active
+ = render partial: 'devise/sessions/new_ldap'
+ %div#tab-signin.tab-pane
+ = render partial: 'devise/sessions/new_base'
+
+ - else
+ = render partial: 'devise/sessions/new_base'
+
+
+ = render 'devise/sessions/oauth_providers' if devise_mapping.omniauthable?
+
+ - if Gitlab.config.gitlab.signup_enabled
+ %hr
+ %div
Don't have an account?
- = link_to "Sign up", new_registration_path(resource_name)
- - if devise_mapping.omniauthable? && resource_class.omniauth_providers.present?
- %hr
- %div
- %span Sign in with: &nbsp;
- - resource_class.omniauth_providers.each do |provider|
- %span
- = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
+ %strong
+ = link_to "Sign up", new_registration_path(resource_name)
+
+ - if extra_config.has_key?('sign_in_text')
+ %hr
+ = markdown(extra_config.sign_in_text)
diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb
index d7499d14ec5..a47b5ff1ec7 100644
--- a/app/views/devise/shared/_links.erb
+++ b/app/views/devise/shared/_links.erb
@@ -1,5 +1,5 @@
<%- if controller_name != 'sessions' %>
- <%= link_to "Sign in", new_session_path(resource_name), :class => "btn" %><br />
+ <%= link_to "Sign in", new_session_path(resource_name), class: "btn" %><br />
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
@@ -7,7 +7,7 @@
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
-<%= link_to "Forgot your password?", new_password_path(resource_name), :class => "btn" %><br />
+<%= link_to "Forgot your password?", new_password_path(resource_name), class: "btn" %><br />
<% end -%>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb
index b787e648ca2..f9277d1673f 100644
--- a/app/views/devise/unlocks/new.html.erb
+++ b/app/views/devise/unlocks/new.html.erb
@@ -1,6 +1,6 @@
<h2>Resend unlock instructions</h2>
-<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
+<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
@@ -9,4 +9,4 @@
<div><%= f.submit "Resend unlock instructions" %></div>
<% end %>
-<%= render :partial => "devise/shared/links" %>
+<%= render partial: "devise/shared/links" %>
diff --git a/app/views/tree/edit.html.haml b/app/views/edit_tree/show.html.haml
index 81918e509b8..17d813ce75e 100644
--- a/app/views/tree/edit.html.haml
+++ b/app/views/edit_tree/show.html.haml
@@ -1,24 +1,24 @@
.file-editor
- = form_tag(project_tree_path(@project, @id), method: :put, class: "form-horizontal") do
+ = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
.file_holder
.file_title
%i.icon-file
%span.file_name
- = @tree.path
+ = @path
%small
on
%strong= @ref
%span.options
.btn-group.tree-btn-group
- = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-tiny btn-cancel", confirm: "Are you sure?"
+ = link_to "Cancel", project_blob_path(@project, @id), class: "btn btn-tiny btn-cancel", confirm: leave_edit_message
.file_content.code
- %pre#editor= @tree.data
+ %pre#editor= @blob.data
.control-group.commit_message-group
= label_tag 'commit_message', class: "control-label" do
Commit message
.controls
- = text_area_tag 'commit_message', '', placeholder: "Update #{@tree.name}", required: true, rows: 3
+ = text_area_tag 'commit_message', '', placeholder: "Update #{@blob.name}", required: true, rows: 3
.form-actions
= hidden_field_tag 'last_commit', @last_commit
= hidden_field_tag 'content', '', id: :file_content
@@ -27,10 +27,11 @@
.message
to branch
%strong= @ref
- = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-cancel", confirm: "Are you sure?"
+ = link_to "Cancel", project_blob_path(@project, @id), class: "btn btn-cancel", confirm: leave_edit_message
:javascript
- var ace_mode = "#{@tree.language.try(:ace_mode)}";
+ ace.config.set("modePath", "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
+ var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
if (ace_mode) {
editor.getSession().setMode('ace/mode/' + ace_mode);
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index ea417aa9f30..2d80fc103f6 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,8 +1,7 @@
-- commit = CommitDecorator.decorate(commit)
%li.commit
%p
- = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
- %span= commit.author_name
+ = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id"
+ %span= commit[:author][:name]
&ndash;
- = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
- = gfm escape_once(truncate(commit.title, length: 50)) rescue "--broken encoding"
+ = image_tag gravatar_icon(commit[:author][:email]), class: "avatar", width: 16
+ = gfm escape_once(truncate(commit[:message], length: 50)) rescue "--broken encoding"
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index d09e6e03f01..e44b366040f 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -1,12 +1,12 @@
-%div{:xmlns => "http://www.w3.org/1999/xhtml"}
+%div{xmlns: "http://www.w3.org/1999/xhtml"}
- event.commits.first(15).each do |commit|
%p
- %strong= commit.author_name
- = link_to "(##{commit.short_id})", project_commit_path(event.project, :id => commit.id)
+ %strong= commit[:author][:name]
+ = link_to "(##{commit[:id][0...8]})", project_commit_path(event.project, id: commit[:id])
%i
at
- = commit.committed_date.strftime("%Y-%m-%d %H:%M:%S")
- %blockquote= simple_format(escape_once(commit.safe_message))
+ = commit[:timestamp].to_time.to_s(:short)
+ %blockquote= simple_format(escape_once(commit[:message]))
- if event.commits_count > 15
%p
%i
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index 53cbe1c94ce..05d3832c7f9 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -2,11 +2,15 @@
%span.author_name= link_to_author event
%span.event_label{class: event.action_name}= event_action_name(event)
- if event.target
- %strong= link_to_gfm truncate(event.target_title), [event.project, event.target]
+ %strong= link_to "##{event.target_id}", [event.project, event.target]
- else
- %strong= gfm truncate(event.target_title)
+ %strong= gfm event.target_title
at
- if event.project
= link_to_project event.project
- else
= event.project_name
+.event-body
+ .event-note
+ - if event.target.respond_to?(:title)
+ = event.target.title
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 119b8e828d0..f2b8dc4238c 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -21,5 +21,5 @@
%li.commits-stat
- if event.commits_count > 2
%span ... and #{event.commits_count - 2} more commits.
- = link_to project_compare_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do
- %strong Compare &rarr; #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]}
+ = link_to project_compare_path(event.project, from: event.commit_from, to: event.commit_to) do
+ %strong Compare &rarr; #{event.commit_from[0..7]}...#{event.commit_to[0..7]}
diff --git a/app/views/graph/_head.html.haml b/app/views/graph/_head.html.haml
index fba9a958a19..7a5b3c6f43d 100644
--- a/app/views/graph/_head.html.haml
+++ b/app/views/graph/_head.html.haml
@@ -3,14 +3,24 @@
.clearfix
.pull-left
- = render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path}
+ = render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
+ .pull-left
+ = form_tag project_graph_path(@project, @id), method: :get do |f|
+ .control-group
+ = label_tag :filter_ref, "Show only selected ref", class: 'control-label light'
+ .controls
+ = check_box_tag :filter_ref, 1, @options[:filter_ref]
+ - @options.each do |key, value|
+ = hidden_field_tag(key, value, id: nil) unless key == "filter_ref"
.search.pull-right
- = form_tag project_graph_path(@project, params[:id]), method: :get do |f|
+ = form_tag project_graph_path(@project, @id), method: :get do |f|
.control-group
= label_tag :search , "Looking for commit:", class: 'control-label light'
.controls
- = text_field_tag :q, @q, placeholder: "Input SHA", class: "search-input xlarge"
+ = text_field_tag :q, @options[:q], placeholder: "Input SHA", class: "search-input xlarge"
= button_tag type: 'submit', class: 'btn vtop' do
%i.icon-search
+ - @options.each do |key, value|
+ = hidden_field_tag(key, value, id: nil) unless key == "q"
diff --git a/app/views/graph/show.html.haml b/app/views/graph/show.html.haml
index e45aca1ddcb..0ee6648317c 100644
--- a/app/views/graph/show.html.haml
+++ b/app/views/graph/show.html.haml
@@ -7,11 +7,12 @@
:javascript
var branch_graph;
- $(function(){
- branch_graph = new BranchGraph($("#holder"), {
- url: '#{project_graph_path(@project, @ref, q: @q, format: :json)}',
- commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}',
- ref: '#{@ref}',
- commit_id: '#{@commit.id}'
- });
+ $("#filter_ref").click(function() {
+ $(this).closest('form').submit();
+ });
+ branch_graph = new BranchGraph($("#holder"), {
+ url: '#{project_graph_path(@project, @ref, @options.merge(format: :json))}',
+ commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}',
+ ref: '#{@ref}',
+ commit_id: '#{@commit.id}'
});
diff --git a/app/views/graph/show.json.erb b/app/views/graph/show.json.erb
index d0a0709ac47..9a62cdb3dc9 100644
--- a/app/views/graph/show.json.erb
+++ b/app/views/graph/show.json.erb
@@ -7,13 +7,13 @@
{
parents: parents_zip_spaces(c.parents(@graph.map), c.parent_spaces),
author: {
- name: c.author.name,
- email: c.author.email,
- icon: gravatar_icon(c.author.email, 20)
+ name: c.author_name,
+ email: c.author_email,
+ icon: gravatar_icon(c.author_email, 20)
},
time: c.time,
space: c.spaces.first,
- refs: join_with_space(c.refs),
+ refs: get_refs(c),
id: c.sha,
date: c.date,
message: c.message,
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index eb4f324b358..0f8c140c067 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -26,7 +26,7 @@
.pull-right
= link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Remove', project, 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
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 96aa2a1626d..6d642b65cbd 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -14,7 +14,7 @@
- project = group[0]
%h5.title
= link_to_project project
- %ul.well-list.issues_table
+ %ul.well-list.issues-list
- group[1].each do |issue|
= render issue
%hr
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 36ee4922731..b395a8bc6a3 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -24,5 +24,5 @@
%li Group is kind of directory for several projects
%li All created groups are private
%li People within a group see only projects they have access to
- %li All projects of group will be stored in group directory
+ %li All projects of group will be stored in a group directory
%li You will be able to move existing projects into group
diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder
index 5f2999c3d8e..edf03642d82 100644
--- a/app/views/groups/show.atom.builder
+++ b/app/views/groups/show.atom.builder
@@ -8,10 +8,9 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
@events.each do |event|
if event.proper?
- event = EventDecorator.decorate(event)
xml.entry do
- event_link = event.feed_url
- event_title = event.feed_title
+ event_link = event_feed_url(event)
+ event_title = event_feed_title(event)
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link :href => event_link
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index adf249f656a..1ce008f7e85 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,4 +1,4 @@
-.projects
+.dashboard
.activities.span8
= render "events/event_last_push", event: @last_push
= link_to dashboard_path, class: 'btn btn-tiny' do
@@ -13,7 +13,7 @@
.loading.hide
.side.span4
- if @group.description.present?
- .description.well.light
+ .description.well.well-small.light
= @group.description
= render "projects", projects: @projects
.prepend-top-20
@@ -23,10 +23,4 @@
News Feed
%hr
- .gitlab-promo
- = link_to "Homepage", "http://gitlabhq.com"
- = link_to "Blog", "http://blog.gitlabhq.com"
- = link_to "@gitlabhq", "https://twitter.com/gitlabhq"
-
-:javascript
- $(function(){ Pager.init(20, true); });
+ = render 'shared/promo'
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index ffea654df73..1685c6eec53 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -19,7 +19,7 @@
%ul.well-list
%li
Email your
- = mail_to Gitlab.config.gitlab.support_email, "support contact"
+ = mail_to gitlab_config.support_email, "support contact"
%li
Use the
= link_to "search bar", '#', onclick: "$('#search').focus();"
@@ -27,6 +27,8 @@
%li
Ask in our
= link_to "support forum", "https://groups.google.com/forum/#!forum/gitlabhq"
+ or on
+ = link_to "Stack Overflow", "http://stackoverflow.com/questions/tagged/gitlab"
%li
Browse our
= link_to "issue tracker", "https://github.com/gitlabhq/gitlabhq/issues"
diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml
index b621f11bc5b..8495c323cb8 100644
--- a/app/views/issues/_filter.html.haml
+++ b/app/views/issues/_filter.html.haml
@@ -1,7 +1,7 @@
= form_tag project_issues_path(@project), method: 'get' do
%fieldset
%ul.nav.nav-pills.nav-stacked
- %li{class: ("active" if !params[:status])}
+ %li{class: ("active" if !params[:status] || params[:status].blank?)}
= link_to project_issues_path(@project, status: nil) do
Open
%li{class: ("active" if params[:status] == 'assigned-to-me')}
diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml
index 6d7613a700d..2bb5e6ca5ac 100644
--- a/app/views/issues/_form.html.haml
+++ b/app/views/issues/_form.html.haml
@@ -19,7 +19,9 @@
= f.label :assignee_id do
%i.icon-user
Assign to
- .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
+ .input
+ = f.select(:assignee_id, @project.users.alphabetically.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
+ = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.issue_milestone.pull-left
= f.label :milestone_id do
%i.icon-time
@@ -38,7 +40,7 @@
.clearfix
= f.label :description, "Details"
.input
- = f.text_area :description, maxlength: 2000, class: "xxlarge js-gfm-input", rows: 14
+ = f.text_area :description, class: "xxlarge js-gfm-input", rows: 14
%p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
@@ -55,31 +57,33 @@
:javascript
- $(function(){
- $("#issue_label_list")
- .bind( "keydown", function( event ) {
- if ( event.keyCode === $.ui.keyCode.TAB &&
- $( this ).data( "autocomplete" ).menu.active ) {
- event.preventDefault();
- }
- })
- .autocomplete({
- minLength: 0,
- source: function( request, response ) {
- response( $.ui.autocomplete.filter(
- #{raw labels_autocomplete_source}, extractLast( request.term ) ) );
- },
- focus: function() {
- return false;
- },
- select: function(event, ui) {
- var terms = split( this.value );
- terms.pop();
- terms.push( ui.item.value );
- terms.push( "" );
- this.value = terms.join( ", " );
- return false;
- }
- });
- });
+ $("#issue_label_list")
+ .bind( "keydown", function( event ) {
+ if ( event.keyCode === $.ui.keyCode.TAB &&
+ $( this ).data( "autocomplete" ).menu.active ) {
+ event.preventDefault();
+ }
+ })
+ .autocomplete({
+ minLength: 0,
+ source: function( request, response ) {
+ response( $.ui.autocomplete.filter(
+ #{raw labels_autocomplete_source}, extractLast( request.term ) ) );
+ },
+ focus: function() {
+ return false;
+ },
+ select: function(event, ui) {
+ var terms = split( this.value );
+ terms.pop();
+ terms.push( ui.item.value );
+ terms.push( "" );
+ this.value = terms.join( ", " );
+ return false;
+ }
+ });
+ $('.assign-to-me-link').on('click', function(e){
+ $('#issue_assignee_id').val("#{current_user.id}").trigger("liszt:updated");
+ e.preventDefault();
+ });
diff --git a/app/views/issues/_issue.html.haml b/app/views/issues/_issue.html.haml
index 3d1ecd43881..f44c0a6c81f 100644
--- a/app/views/issues/_issue.html.haml
+++ b/app/views/issues/_issue.html.haml
@@ -1,12 +1,37 @@
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: project_issue_path(issue.project, issue) }
- if controller.controller_name == 'issues'
- .issue_check
+ .issue-check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
- .pull-right
+
+ .issue-title
+ %span.light= "##{issue.id}"
+ = link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title"
+
+ .issue-info
+ - if issue.assignee
+ assigned to #{link_to_member(@project, issue.assignee)}
+ - else
+ unassigned
+ - if issue.votes_count > 0
+ = render 'votes/votes_inline', votable: issue
- if issue.notes.any?
- %span.btn.btn-small.disabled.grouped
- %i.icon-comment
+ %span
+ %i.icon-comments
= issue.notes.count
+ - if issue.milestone_id?
+ %span
+ %i.icon-time
+ = issue.milestone.title
+ .pull-right
+ %small updated #{time_ago_in_words(issue.updated_at)} ago
+
+ .issue-labels
+ - issue.labels.each do |label|
+ %span{class: "label #{label_css_class(label.name)}"}
+ %i.icon-tag
+ = label.name
+
+ .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
@@ -16,24 +41,4 @@
%i.icon-edit
Edit
- - if issue.assignee
- = image_tag gravatar_icon(issue.assignee_email), class: "avatar"
- - else
- = image_tag "no_avatar.png", class: "avatar"
-
- %p= link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title"
-
- %span.update-author
- %span.cdark= "##{issue.id}"
- - if issue.assignee
- assigned to #{issue.assignee_name}
- - else
- &nbsp;
- - if issue.votes_count > 0
- = render 'votes/votes_inline', votable: issue
- %span
- - issue.labels.each do |label|
- %span.label
- %i.icon-tag
- = label.name
diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml
index dc7db9061ac..cc8d8d9cae2 100644
--- a/app/views/issues/_issues.html.haml
+++ b/app/views/issues/_issues.html.haml
@@ -1,12 +1,94 @@
-= render @issues
+.ui-box
+ .title
+ = 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_issues_text Update selected issues with &nbsp;
+ .left
+ = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
+ = select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")
+ = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), 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_issues_with_filter_path(@project, label_name: nil) do
+ Any
+ - issue_label_names.each do |label_name|
+ %li
+ = link_to project_issues_with_filter_path(@project, 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_issues_with_filter_path(@project, assignee_id: nil) do
+ Any
+ = link_to project_issues_with_filter_path(@project, assignee_id: 0) do
+ Unassigned
+ - @project.users.sort_by(&:name).each do |user|
+ %li
+ = link_to project_issues_with_filter_path(@project, assignee_id: user.id) do
+ = image_tag gravatar_icon(user.email), class: "avatar s16"
+ = 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"
+ Unspecified
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_issues_with_filter_path(@project, milestone_id: nil) do
+ Any
+ = link_to project_issues_with_filter_path(@project, milestone_id: 0) do
+ Unspecified
+ - issues_active_milestones.each do |milestone|
+ %li
+ = link_to project_issues_with_filter_path(@project, milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
+
+
+ %ul.well-list.issues-list
+ = render @issues
+ - if @issues.blank?
+ %li
+ %h4.nothing_here_message Nothing to show here
- if @issues.present?
- %li.bottom
- .left= paginate @issues, remote: true, theme: "gitlab"
- .pull-right
- %span.issue_counter #{@issues.total_count}
- issues for this filter
-- else
- %li
- %h4.nothing_here_message Nothing to show here
+ .pull-right
+ %span.issue_counter #{@issues.total_count}
+ issues for this filter
+ = paginate @issues, remote: true, theme: "gitlab"
diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml
index 875f29e2600..bf33769349a 100644
--- a/app/views/issues/index.html.haml
+++ b/app/views/issues/index.html.haml
@@ -4,47 +4,22 @@
Issues
%span (<span class=issue_counter>#{@issues.total_count}</span>)
.pull-right
- .span5
+ .span6
- 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-primary pull-right", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
New Issue
- = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right' do
- = hidden_field_tag :project_id, @project.id, { id: 'project_id' }
- = hidden_field_tag :status, params[:status]
- = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 pull-right neib search-text-input' }
+ = form_tag project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right' do
+ = hidden_field_tag :status, params[:status], id: 'search_status'
+ = hidden_field_tag :assignee_id, params[:assignee_id], id: 'search_assignee_id'
+ = hidden_field_tag :milestone_id, params[:milestone_id], id: 'search_milestone_id'
+ = hidden_field_tag :label_name, params[:label_name], id: 'search_label_name'
+ = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search input-xlarge append-right-10 search-text-input' }
.clearfix
.row
.span3
= render 'filter', entity: 'issue'
- .span9
- %div#issues-table-holder.ui-box
- .title
- = 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_issues_text Update selected issues with &nbsp;
- .left
- = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
- = select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")
- = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), 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
- = form_tag project_issues_path(@project), method: :get do
- = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), prompt: "Labels")
- = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")
- = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone")
- = hidden_field_tag :status, params[:status]
-
- %ul#issues-table.well-list.issues_table
- = render "issues"
-
-:javascript
- $(function(){
- issuesPage();
- })
+ .span9.issues-holder
+ = render "issues"
diff --git a/app/views/issues/index.js.haml b/app/views/issues/index.js.haml
index 48d7f582be2..1be6a64f535 100644
--- a/app/views/issues/index.js.haml
+++ b/app/views/issues/index.js.haml
@@ -1,2 +1,4 @@
:plain
- $('#issues-table').html("#{escape_javascript(render('issues'))}");
+ $('.issues-holder').html("#{escape_javascript(render('issues'))}");
+ History.replaceState({path: "#{request.url}"}, document.title, "#{request.url}");
+ Issues.reload();
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 70f94e52942..2e204b8240d 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -6,6 +6,9 @@
= @issue.created_at.stamp("Aug 21, 2011")
%span.pull-right
+ = link_to new_project_issue_path(@project), class: "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"
@@ -44,7 +47,7 @@
.pull-right
- @issue.labels.each do |label|
- %span.label
+ %span{class: "label #{label_css_class(label.name)}"}
%i.icon-tag
= label.name
&nbsp;
diff --git a/app/views/kaminari/admin/_first_page.html.haml b/app/views/kaminari/admin/_first_page.html.haml
deleted file mode 100644
index 41c9c0b3af6..00000000000
--- a/app/views/kaminari/admin/_first_page.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# Link to the "First" page
--# available local variables
--# url: url to the first page
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%span.first
- = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote
diff --git a/app/views/kaminari/admin/_gap.html.haml b/app/views/kaminari/admin/_gap.html.haml
deleted file mode 100644
index 3ffd12f8587..00000000000
--- a/app/views/kaminari/admin/_gap.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# Non-link tag that stands for skipped pages...
--# available local variables
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%li{class: "page"}
- %span.page.gap
- = raw(t 'views.pagination.truncate')
diff --git a/app/views/kaminari/admin/_last_page.html.haml b/app/views/kaminari/admin/_last_page.html.haml
deleted file mode 100644
index b03a206224c..00000000000
--- a/app/views/kaminari/admin/_last_page.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# Link to the "Last" page
--# available local variables
--# url: url to the last page
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%span.last
- = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote}
diff --git a/app/views/kaminari/admin/_next_page.html.haml b/app/views/kaminari/admin/_next_page.html.haml
deleted file mode 100644
index 00c5f0b6f4e..00000000000
--- a/app/views/kaminari/admin/_next_page.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# Link to the "Next" page
--# available local variables
--# url: url to the next page
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%li.next
- = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
diff --git a/app/views/kaminari/admin/_page.html.haml b/app/views/kaminari/admin/_page.html.haml
deleted file mode 100644
index a52d883b9a8..00000000000
--- a/app/views/kaminari/admin/_page.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
--# Link showing page number
--# available local variables
--# page: a page object for "this" page
--# url: url to this page
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%li{class: "page#{' active' if page.current?}"}
- = link_to page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil}
diff --git a/app/views/kaminari/admin/_paginator.html.haml b/app/views/kaminari/admin/_paginator.html.haml
deleted file mode 100644
index 6f9fb332261..00000000000
--- a/app/views/kaminari/admin/_paginator.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
--# The container tag
--# available local variables
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
--# paginator: the paginator that renders the pagination tags inside
-= paginator.render do
- %div.pagination
- %ul
- = prev_page_tag unless current_page.first?
- - each_page do |page|
- - if page.left_outer? || page.right_outer? || page.inside_window?
- = page_tag page
- - elsif !page.was_truncated?
- = gap_tag
- = next_page_tag unless current_page.last?
diff --git a/app/views/kaminari/admin/_prev_page.html.haml b/app/views/kaminari/admin/_prev_page.html.haml
deleted file mode 100644
index f673abdb3ae..00000000000
--- a/app/views/kaminari/admin/_prev_page.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
--# Link to the "Previous" page
--# available local variables
--# url: url to the previous page
--# current_page: a page object for the currently displayed page
--# num_pages: total number of pages
--# per_page: number of items to fetch per page
--# remote: data-remote
-%li{class: "prev" }
- = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
diff --git a/app/views/kaminari/gitlab/_gap.html.haml b/app/views/kaminari/gitlab/_gap.html.haml
index f82f185ac35..3ffd12f8587 100644
--- a/app/views/kaminari/gitlab/_gap.html.haml
+++ b/app/views/kaminari/gitlab/_gap.html.haml
@@ -4,5 +4,6 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%span.page.gap
- = raw(t 'views.pagination.truncate')
+%li{class: "page"}
+ %span.page.gap
+ = raw(t 'views.pagination.truncate')
diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml
index 296cceb080b..00c5f0b6f4e 100644
--- a/app/views/kaminari/gitlab/_next_page.html.haml
+++ b/app/views/kaminari/gitlab/_next_page.html.haml
@@ -5,5 +5,5 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%span.next
+%li.next
= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
diff --git a/app/views/kaminari/gitlab/_page.html.haml b/app/views/kaminari/gitlab/_page.html.haml
index 19456dcc058..a52d883b9a8 100644
--- a/app/views/kaminari/gitlab/_page.html.haml
+++ b/app/views/kaminari/gitlab/_page.html.haml
@@ -6,5 +6,5 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%span{class: "page#{' current' if page.current?}"}
- = link_to_unless page.current?, page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil}
+%li{class: "page#{' active' if page.current?}"}
+ = link_to page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil}
diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml
index 6dd5a5782a2..6f9fb332261 100644
--- a/app/views/kaminari/gitlab/_paginator.html.haml
+++ b/app/views/kaminari/gitlab/_paginator.html.haml
@@ -6,11 +6,12 @@
-# remote: data-remote
-# paginator: the paginator that renders the pagination tags inside
= paginator.render do
- %nav.gitlab_pagination
- = prev_page_tag
- - each_page do |page|
- - if page.left_outer? || page.right_outer? || page.inside_window?
- = page_tag page
- - elsif !page.was_truncated?
- = gap_tag
- = next_page_tag
+ %div.pagination
+ %ul
+ = prev_page_tag unless current_page.first?
+ - each_page do |page|
+ - if page.left_outer? || page.right_outer? || page.inside_window?
+ = page_tag page
+ - elsif !page.was_truncated?
+ = gap_tag
+ = next_page_tag unless current_page.last?
diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml
index 5c2061690ac..f673abdb3ae 100644
--- a/app/views/kaminari/gitlab/_prev_page.html.haml
+++ b/app/views/kaminari/gitlab/_prev_page.html.haml
@@ -5,5 +5,5 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%span.prev
+%li{class: "prev" }
= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
diff --git a/app/views/labels/_label.html.haml b/app/views/labels/_label.html.haml
index 027b041d58e..2b1aafc546b 100644
--- a/app/views/labels/_label.html.haml
+++ b/app/views/labels/_label.html.haml
@@ -1,9 +1,15 @@
+- frequency = @project.issues.tagged_with(label.name).count
%li
%strong
- %i.icon-tag
- = label.name
+ %span{class: "label #{label_css_class(label.name)}"}
+ %i.icon-tag
+ - if frequency.zero?
+ %span.light= label.name
+ - else
+ = label.name
.pull-right
- = link_to project_issues_path(label_name: label.name) do
- %strong
- = pluralize(label.count, 'issue')
- = "»"
+ - unless frequency.zero?
+ = link_to project_issues_path(label_name: label.name) do
+ %strong
+ = pluralize(frequency, 'issue')
+ = "»"
diff --git a/app/views/labels/index.html.haml b/app/views/labels/index.html.haml
index 6eb2c00e56d..53f411d932c 100644
--- a/app/views/labels/index.html.haml
+++ b/app/views/labels/index.html.haml
@@ -3,12 +3,12 @@
%h3.page_title
Labels
%br
-%div.ui-box
- %ul.well-list.labels-table
+
+- if @labels.present?
+ %ul.bordered-list.labels-table
- @labels.each do |label|
= render 'label', label: label
- - unless @labels.present?
- %li
- %h3.nothing_here_message Nothing to show here
-
+- 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
diff --git a/app/views/layouts/_google_analytics.html.haml b/app/views/layouts/_google_analytics.html.haml
new file mode 100644
index 00000000000..81e03c7eff2
--- /dev/null
+++ b/app/views/layouts/_google_analytics.html.haml
@@ -0,0 +1,10 @@
+:javascript
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index eb83fd2fd45..0775abea3dd 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -9,6 +9,8 @@
= csrf_meta_tags
= include_gon
+ = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
+
-# Atom feed
- if current_user
- if controller_name == 'projects' && action_name == 'index'
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 8f6873e1dfc..2ea6c3e46d9 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -9,6 +9,11 @@
%h1.project_name= title
%ul.nav
%li
+ %a
+ %div.hide.turbolink-spinner
+ %i.icon-refresh.icon-spin
+ Loading...
+ %li
= render "layouts/search"
%li
= link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
@@ -31,5 +36,3 @@
= link_to current_user, class: "profile-pic" do
= image_tag gravatar_icon(current_user.email, 26)
-
-= render "layouts/init_auto_complete"
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 8f8c7d8885e..3549794b90d 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -1,17 +1,6 @@
:javascript
$(function() {
- GitLab.GfmAutoComplete.Members.url = "#{ "/api/v3/projects/#{@project.id}/members" if @project }";
- GitLab.GfmAutoComplete.Members.params.private_token = "#{current_user.private_token}";
-
- GitLab.GfmAutoComplete.Emoji.data = #{raw emoji_autocomplete_source};
- // convert the list so that the items have the right format for completion
- GitLab.GfmAutoComplete.Emoji.data = $.map(GitLab.GfmAutoComplete.Emoji.data, function(value) {
- return {
- name: value,
- insert: value+':',
- image: '#{image_path("emoji")}/'+value+'.png'
- }
- });
-
+ GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}"
+ GitLab.GfmAutoComplete.Emoji.assetBase = '#{image_path("emoji")}'
GitLab.GfmAutoComplete.setup();
});
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index c484af04704..a43a46b8726 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -2,12 +2,9 @@
= form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f|
= text_field_tag "search", nil, placeholder: "Search", class: "search-input"
= hidden_field_tag :group_id, @group.try(:id)
- = hidden_field_tag :project_id, @project.try(:id)
-
-:javascript
- $(function(){
- $("#search").autocomplete({
- source: #{raw search_autocomplete_source},
- select: function(event, ui) { location.href = ui.item.url }
- });
- });
+ - if @project && @project.persisted?
+ = hidden_field_tag :project_id, @project.id
+ = 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 }
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index 00a08e6131d..3a23cbdb376 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,27 +1,11 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Admin area"
- %body{class: "#{app_theme} admin"}
+ %body{class: "#{app_theme} admin", :'data-page' => body_data_page}
= render "layouts/head_panel", title: "Admin area"
= render "layouts/flash"
- .container
- %ul.main_menu
- = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
- = link_to admin_root_path, title: "Stats" do
- %i.icon-home
- = nav_link(controller: :projects) do
- = link_to "Projects", admin_projects_path
- = nav_link(controller: :teams) do
- = link_to "Teams", admin_teams_path
- = nav_link(controller: :groups) do
- = link_to "Groups", admin_groups_path
- = nav_link(controller: :users) do
- = link_to "Users", admin_users_path
- = nav_link(controller: :logs) do
- = link_to "Logs", admin_logs_path
- = nav_link(controller: :hooks) do
- = link_to "Hooks", admin_hooks_path
- = nav_link(controller: :resque) do
- = link_to "Background Jobs", admin_resque_path
+ %nav.main-nav
+ .container= render 'layouts/nav/admin'
+ .container
.content= yield
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 90c2653438d..792fe5e4a28 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -1,28 +1,11 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Dashboard"
- %body{class: "#{app_theme} application"}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page }
= render "layouts/head_panel", title: "Dashboard"
= render "layouts/flash"
- .container
- %ul.main_menu
- = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
- = link_to root_path, title: "Home" do
- %i.icon-home
- = nav_link(path: 'dashboard#projects') do
- = link_to projects_dashboard_path do
- Projects
- = nav_link(path: 'dashboard#issues') do
- = link_to issues_dashboard_path do
- Issues
- %span.count= current_user.assigned_issues.opened.count
- = nav_link(path: 'dashboard#merge_requests') do
- = link_to merge_requests_dashboard_path do
- Merge Requests
- %span.count= current_user.cared_merge_requests.opened.count
- = nav_link(path: 'search#show') do
- = link_to "Search", search_path
- = nav_link(controller: :help) do
- = link_to "Help", help_path
+ %nav.main-nav
+ .container= render 'layouts/nav/dashboard'
+ .container
.content= yield
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 45528281ed0..0e955d59ff8 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,28 +1,11 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "#{@group.name}"
- %body{class: "#{app_theme} application"}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/head_panel", title: "group: #{@group.name}"
= render "layouts/flash"
- .container
- %ul.main_menu
- = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
- = link_to group_path(@group), title: "Home" do
- %i.icon-home
- = 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
- = 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
- = nav_link(path: 'groups#people') do
- = link_to "People", people_group_path(@group)
-
- - if can?(current_user, :manage_group, @group)
- = nav_link(path: 'groups#edit') do
- = link_to edit_group_path(@group), class: "tab " do
- Settings
+ %nav.main-nav
+ .container= render 'layouts/nav/group'
+ .container
.content= yield
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
new file mode 100644
index 00000000000..e9ca29ea3be
--- /dev/null
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -0,0 +1,19 @@
+%ul
+ = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
+ = link_to admin_root_path, title: "Stats" do
+ %i.icon-home
+ = nav_link(controller: :projects) do
+ = link_to "Projects", admin_projects_path
+ = nav_link(controller: :teams) do
+ = link_to "Teams", admin_teams_path
+ = nav_link(controller: :groups) do
+ = link_to "Groups", admin_groups_path
+ = nav_link(controller: :users) do
+ = link_to "Users", admin_users_path
+ = nav_link(controller: :logs) do
+ = link_to "Logs", admin_logs_path
+ = nav_link(controller: :hooks) do
+ = link_to "Hooks", admin_hooks_path
+ = nav_link(controller: :background_jobs) do
+ = link_to "Background Jobs", admin_background_jobs_path
+
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
new file mode 100644
index 00000000000..2ac35050b64
--- /dev/null
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -0,0 +1,20 @@
+%ul
+ = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
+ = link_to root_path, title: "Home" do
+ %i.icon-home
+ = nav_link(path: 'dashboard#projects') do
+ = link_to projects_dashboard_path do
+ Projects
+ = nav_link(path: 'dashboard#issues') do
+ = link_to issues_dashboard_path do
+ Issues
+ %span.count= current_user.assigned_issues.opened.count
+ = nav_link(path: 'dashboard#merge_requests') do
+ = link_to merge_requests_dashboard_path do
+ Merge Requests
+ %span.count= current_user.cared_merge_requests.opened.count
+ = nav_link(path: 'search#show') do
+ = link_to "Search", search_path
+ = nav_link(controller: :help) do
+ = link_to "Help", help_path
+
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
new file mode 100644
index 00000000000..f3cdb5ac457
--- /dev/null
+++ b/app/views/layouts/nav/_group.html.haml
@@ -0,0 +1,20 @@
+%ul
+ = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
+ = link_to group_path(@group), title: "Home" do
+ %i.icon-home
+ = 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
+ = 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
+ = nav_link(path: 'groups#people') do
+ = link_to "People", people_group_path(@group)
+
+ - if can?(current_user, :manage_group, @group)
+ = nav_link(path: 'groups#edit') do
+ = link_to edit_group_path(@group), class: "tab " do
+ Settings
+
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
new file mode 100644
index 00000000000..e5e4b27c665
--- /dev/null
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -0,0 +1,17 @@
+%ul
+ = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
+ = link_to profile_path, title: "Profile" do
+ %i.icon-home
+ = nav_link(path: 'profiles#account') do
+ = link_to "Account", account_profile_path
+ = nav_link(controller: :notifications) do
+ = link_to "Notifications", profile_notifications_path
+ = nav_link(controller: :keys) do
+ = link_to keys_path do
+ SSH Keys
+ %span.count= current_user.keys.count
+ = nav_link(path: 'profiles#design') do
+ = link_to "Design", design_profile_path
+ = nav_link(path: 'profiles#history') do
+ = link_to "History", history_profile_path
+
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
new file mode 100644
index 00000000000..ec3da964037
--- /dev/null
+++ b/app/views/layouts/nav/_project.html.haml
@@ -0,0 +1,43 @@
+%ul
+ = nav_link(path: 'projects#show', html_options: {class: "home"}) do
+ = link_to project_path(@project), title: "Project" do
+ %i.icon-home
+
+ - unless @project.empty_repo?
+ - if can? current_user, :download_code, @project
+ = nav_link(controller: %w(tree blob blame)) do
+ = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref)
+ = nav_link(controller: %w(commit commits compare repositories protected_branches)) do
+ = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref)
+ = nav_link(controller: %w(graph)) do
+ = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref)
+
+ - if @project.issues_enabled
+ = nav_link(controller: %w(issues milestones labels)) do
+ = link_to url_for_project_issues do
+ Issues
+ - if @project.used_default_issues_tracker?
+ %span.count.issue_counter= @project.issues.opened.count
+
+ - if @project.repo_exists? && @project.merge_requests_enabled
+ = nav_link(controller: :merge_requests) do
+ = link_to project_merge_requests_path(@project) do
+ Merge Requests
+ %span.count.merge_counter= @project.merge_requests.opened.count
+
+ - if @project.wiki_enabled
+ = nav_link(controller: :wikis) do
+ = link_to 'Wiki', project_wiki_path(@project, :home)
+
+ - if @project.wall_enabled
+ = nav_link(controller: :walls) do
+ = link_to 'Wall', project_wall_path(@project)
+
+ - if @project.snippets_enabled
+ = nav_link(controller: :snippets) do
+ = link_to 'Snippets', project_snippets_path(@project)
+
+ - if can? current_user, :admin_project, @project
+ = nav_link(html_options: {class: "#{project_tab_class}"}) do
+ = link_to edit_project_path(@project), class: "stat-tab tab " do
+ Settings
diff --git a/app/views/layouts/nav/_team.html.haml b/app/views/layouts/nav/_team.html.haml
new file mode 100644
index 00000000000..415e45104df
--- /dev/null
+++ b/app/views/layouts/nav/_team.html.haml
@@ -0,0 +1,25 @@
+%ul
+ = nav_link(path: 'teams#show', html_options: {class: 'home'}) do
+ = link_to team_path(@team), title: "Home" do
+ %i.icon-home
+
+ = nav_link(path: 'teams#issues') do
+ = link_to issues_team_path(@team) do
+ Issues
+ %span.count= Issue.opened.of_user_team(@team).count
+
+ = nav_link(path: 'teams#merge_requests') do
+ = link_to merge_requests_team_path(@team) do
+ Merge Requests
+ %span.count= MergeRequest.opened.of_user_team(@team).count
+
+ = nav_link(controller: [:members]) do
+ = link_to team_members_path(@team), class: "team-tab tab" do
+ Members
+ %span.count= @team.members.count
+
+ - if can? current_user, :admin_user_team, @team
+ = nav_link(path: 'teams#edit') do
+ = link_to edit_team_path(@team), class: "stat-tab tab " do
+ Settings
+
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 611063e8c99..30a0532bc2b 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -1,23 +1,11 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Profile"
- %body{class: "#{app_theme} profile"}
+ %body{class: "#{app_theme} profile", :'data-page' => body_data_page}
= render "layouts/head_panel", title: "Profile"
= render "layouts/flash"
- .container
- %ul.main_menu
- = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
- = link_to profile_path, title: "Profile" do
- %i.icon-home
- = nav_link(path: 'profiles#account') do
- = link_to "Account", account_profile_path
- = nav_link(controller: :keys) do
- = link_to keys_path do
- SSH Keys
- %span.count= current_user.keys.count
- = nav_link(path: 'profiles#design') do
- = link_to "Design", design_profile_path
- = nav_link(path: 'profiles#history') do
- = link_to "History", history_profile_path
+ %nav.main-nav
+ .container= render 'layouts/nav/profile'
+ .container
.content= yield
diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml
index ca2f6e9a702..6d8bf9b710b 100644
--- a/app/views/layouts/project_resource.html.haml
+++ b/app/views/layouts/project_resource.html.haml
@@ -1,55 +1,15 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
- %body{class: "#{app_theme} project"}
+ %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/head_panel", title: project_title(@project)
+ = render "layouts/init_auto_complete"
= render "layouts/flash"
- if can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
- .container
- %ul.main_menu
- = nav_link(path: 'projects#show', html_options: {class: "home"}) do
- = link_to project_path(@project), title: "Project" do
- %i.icon-home
-
- - if @project.repo_exists?
- - if can? current_user, :download_code, @project
- = nav_link(controller: %w(tree blob blame)) do
- = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref)
- = nav_link(controller: %w(commit commits compare repositories protected_branches)) do
- = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref)
- = nav_link(controller: %w(graph)) do
- = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref)
-
- - if @project.issues_enabled
- = nav_link(controller: %w(issues milestones labels)) do
- = link_to url_for_project_issues do
- Issues
- - if @project.used_default_issues_tracker?
- %span.count.issue_counter= @project.issues.opened.count
-
- - if @project.repo_exists? && @project.merge_requests_enabled
- = nav_link(controller: :merge_requests) do
- = link_to project_merge_requests_path(@project) do
- Merge Requests
- %span.count.merge_counter= @project.merge_requests.opened.count
-
- - if @project.wiki_enabled
- = nav_link(controller: :wikis) do
- = link_to 'Wiki', project_wiki_path(@project, :home)
-
- - if @project.wall_enabled
- = nav_link(controller: :walls) do
- = link_to 'Wall', project_wall_path(@project)
-
- - if @project.snippets_enabled
- = nav_link(controller: :snippets) do
- = link_to 'Snippets', project_snippets_path(@project)
-
- - if can? current_user, :admin_project, @project
- = nav_link(html_options: {class: "#{project_tab_class}"}) do
- = link_to edit_project_path(@project), class: "stat-tab tab " do
- Settings
+ %nav.main-nav
+ .container= render 'layouts/nav/project'
+ .container
.content= yield
diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml
index 483bfad66ae..e64e68d2446 100644
--- a/app/views/layouts/user_team.html.haml
+++ b/app/views/layouts/user_team.html.haml
@@ -1,33 +1,11 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "#{@team.name}"
- %body{class: "#{app_theme} application"}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/head_panel", title: "team: #{@team.name}"
= render "layouts/flash"
- .container
- %ul.main_menu
- = nav_link(path: 'teams#show', html_options: {class: 'home'}) do
- = link_to team_path(@team), title: "Home" do
- %i.icon-home
-
- = nav_link(path: 'teams#issues') do
- = link_to issues_team_path(@team) do
- Issues
- %span.count= Issue.opened.of_user_team(@team).count
-
- = nav_link(path: 'teams#merge_requests') do
- = link_to merge_requests_team_path(@team) do
- Merge Requests
- %span.count= MergeRequest.opened.of_user_team(@team).count
-
- = nav_link(controller: [:members]) do
- = link_to team_members_path(@team), class: "team-tab tab" do
- Members
- %span.count= @team.members.count
-
- - if can? current_user, :admin_user_team, @team
- = nav_link(path: 'teams#edit') do
- = link_to edit_team_path(@team), class: "stat-tab tab " do
- Settings
+ %nav.main-nav
+ .container= render 'layouts/nav/team'
+ .container
.content= yield
diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml
index 816c852d24b..1c3aca176ab 100644
--- a/app/views/merge_requests/_form.html.haml
+++ b/app/views/merge_requests/_form.html.haml
@@ -13,7 +13,7 @@
.mr_branch_box
%h5.cgray From (Head Branch)
.body
- .padded= f.select(:source_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'})
+ .padded= f.select(:source_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'})
.mr_source_commit
.span2
@@ -22,7 +22,7 @@
.mr_branch_box
%h5.cgray To (Base Branch)
.body
- .padded= f.select(:target_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'})
+ .padded= f.select(:target_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'})
.mr_target_commit
%fieldset
@@ -40,7 +40,7 @@
= f.label :assignee_id do
%i.icon-user
Assign to
- .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
+ .input= f.select(:assignee_id, @project.users.alphabetically.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
.left
= f.label :milestone_id do
%i.icon-time
diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml
index 09c55d98465..ffc6b8fda1e 100644
--- a/app/views/merge_requests/_merge_request.html.haml
+++ b/app/views/merge_requests/_merge_request.html.haml
@@ -1,32 +1,29 @@
%li{ class: mr_css_classes(merge_request) }
- .pull-right
- .left
- - if merge_request.merged?
- %span.btn.btn-small.disabled.grouped
- %strong
- %i.icon-ok
- = "MERGED"
- - if merge_request.notes.any?
- %span.btn.btn-small.disabled.grouped
- %i.icon-comment
- = merge_request.mr_and_commit_notes.count
- - if merge_request.milestone_id?
- %span.btn.btn-small.disabled.grouped
- %i.icon-time
- = merge_request.milestone.title
- %span.btn.btn-small.disabled.grouped
- = merge_request.source_branch
- &rarr;
+ .merge-request-title
+ %span.light= "##{merge_request.id}"
+ = link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.project, merge_request), class: "row_title"
+ - if merge_request.merged?
+ %small.pull-right
+ %i.icon-ok
+ = "MERGED"
+ - else
+ %span.pull-right
+ %i.icon-angle-right
= merge_request.target_branch
- = image_tag gravatar_icon(merge_request.author_email), class: "avatar"
-
- %p= link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.project, merge_request), class: "row_title"
-
- %span.update-author
- %small.cdark= "##{merge_request.id}"
- authored by #{merge_request.author_name}
- = time_ago_in_words(merge_request.created_at)
- ago
-
+ .merge-request-info
+ - if merge_request.author
+ authored by #{link_to_member(@project, merge_request.author)}
- if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request
+ - if merge_request.notes.any?
+ %span
+ %i.icon-comments
+ = merge_request.mr_and_commit_notes.count
+ - if merge_request.milestone_id?
+ %span
+ %i.icon-time
+ = merge_request.milestone.title
+
+
+ .pull-right
+ %small updated #{time_ago_in_words(merge_request.updated_at)} ago
diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml
index 08b80172645..d6e00ca9b8b 100644
--- a/app/views/merge_requests/_show.html.haml
+++ b/app/views/merge_requests/_show.html.haml
@@ -26,14 +26,12 @@
:javascript
var merge_request;
- $(function(){
- merge_request = new MergeRequest({
- url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}",
- check_enable: #{@merge_request.unchecked? ? "true" : "false"},
- url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}",
- ci_enable: #{@project.gitlab_ci? ? "true" : "false"},
- current_status: "#{@merge_request.merge_status_name}",
- action: "#{controller.action_name}"
- });
- });
+ merge_request = new MergeRequest({
+ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}",
+ check_enable: #{@merge_request.unchecked? ? "true" : "false"},
+ url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}",
+ ci_enable: #{@project.gitlab_ci? ? "true" : "false"},
+ current_status: "#{@merge_request.merge_status_name}",
+ action: "#{controller.action_name}"
+ });
diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml
index 3073c8f6bab..b9e9096e3ae 100644
--- a/app/views/merge_requests/index.html.haml
+++ b/app/views/merge_requests/index.html.haml
@@ -20,16 +20,16 @@
= hidden_field_tag :f, params[:f]
.clearfix
- %ul.well-list
+ %ul.well-list.mr-list
= render @merge_requests
- if @merge_requests.blank?
%li
%h4.nothing_here_message Nothing to show here
- - if @merge_requests.present?
- %li.bottom
- .left= paginate @merge_requests, theme: "gitlab"
- .pull-right
- %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+ - if @merge_requests.present?
+ .pull-right
+ %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+
+ = paginate @merge_requests, theme: "gitlab"
:javascript
$(merge_requestsPage);
diff --git a/app/views/merge_requests/show/_commits.html.haml b/app/views/merge_requests/show/_commits.html.haml
index 5e27b6dc25a..eee786d71ef 100644
--- a/app/views/merge_requests/show/_commits.html.haml
+++ b/app/views/merge_requests/show/_commits.html.haml
@@ -22,9 +22,9 @@
= render "commits/commit", commit: commit
- else
- %h5
+ %h4.nothing_here_message
Nothing to merge from
- %span.label #{@merge_request.source_branch}
+ %span.label-branch #{@merge_request.source_branch}
to
- %span.label #{@merge_request.target_branch}
+ %span.label-branch #{@merge_request.target_branch}
%br
diff --git a/app/views/merge_requests/show/_diffs.html.haml b/app/views/merge_requests/show/_diffs.html.haml
index 0807454c4b0..033d66a4ad4 100644
--- a/app/views/merge_requests/show/_diffs.html.haml
+++ b/app/views/merge_requests/show/_diffs.html.haml
@@ -4,7 +4,7 @@
%h4.nothing_here_message
Can't load diff.
You can
- = link_to "download it", project_merge_request_path(@project, @merge_request), format: :diff, class: "vlink"
+ = link_to "download it", project_merge_request_path(@project, @merge_request, format: :diff), class: "vlink"
instead.
- else
%h4.nothing_here_message Nothing to merge
diff --git a/app/views/merge_requests/show/_how_to_merge.html.haml b/app/views/merge_requests/show/_how_to_merge.html.haml
index 69881d4352f..7f1e33418de 100644
--- a/app/views/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/merge_requests/show/_how_to_merge.html.haml
@@ -3,22 +3,17 @@
%a.close{href: "#"} ×
%h3 How To Merge
.modal-body
+ %p
+ %strong Step 1.
+ Checkout target branch and get recent objects from GitLab
%pre.dark
- = preserve do
+ :preserve
git checkout #{@merge_request.target_branch}
git fetch origin
+ %p
+ %strong Step 2.
+ Merge source branch into target branch and push changes to GitLab
+ %pre.dark
+ :preserve
git merge origin/#{@merge_request.source_branch}
git push origin #{@merge_request.target_branch}
-
-
-:javascript
- $(function(){
- var modal = $('#modal_merge_info').modal({modal: true, show:false});
- $('.how_to_merge_link').bind("click", function(){
- modal.show();
- });
- $('.modal-header .close').bind("click", function(){
- modal.hide();
- })
- })
-
diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml
index 3b54f613f58..594f4061c23 100644
--- a/app/views/merge_requests/show/_mr_box.html.haml
+++ b/app/views/merge_requests/show/_mr_box.html.haml
@@ -1,13 +1,13 @@
.ui-box.ui-box-show
.ui-box-head
%h4.box-title
+ = gfm escape_once(@merge_request.title)
- if @merge_request.merged?
- .error.status_info
+ .success.status_info
%i.icon-ok
Merged
- elsif @merge_request.closed?
.error.status_info Closed
- = gfm escape_once(@merge_request.title)
.ui-box-body
%div
@@ -22,13 +22,15 @@
- if @merge_request.closed?
- .ui-box-bottom
+ .ui-box-bottom.alert-error
%span
+ %i.icon-remove
Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
%small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago.
- if @merge_request.merged?
- .ui-box-bottom
+ .ui-box-bottom.alert-success
%span
+ %i.icon-ok
Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
- %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago.
+ #{time_ago_in_words(@merge_request.merge_event.created_at)} ago.
diff --git a/app/views/merge_requests/show/_mr_ci.html.haml b/app/views/merge_requests/show/_mr_ci.html.haml
index a8faa6ba617..9b15c4526e9 100644
--- a/app/views/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/merge_requests/show/_mr_ci.html.haml
@@ -1,4 +1,4 @@
-- if @merge_request.opened? && @commits.any?
+- if @commits.any?
.ci_widget.ci-success{style: "display:none"}
.alert.alert-success
%i.icon-ok
diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml
index 8a3727c6f6a..894fa6c1133 100644
--- a/app/views/milestones/_milestone.html.haml
+++ b/app/views/milestones/_milestone.html.haml
@@ -4,6 +4,8 @@
= link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do
%i.icon-edit
Edit
+ - if milestone.can_be_closed?
+ = link_to 'Close', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove"
%h4
= link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
- if milestone.expired? and not milestone.closed?
@@ -13,11 +15,8 @@
- if milestone.is_empty?
%span.muted Empty
- else
- .row
- .span4
- .progress.progress-info
- .bar{style: "width: #{milestone.percent_complete}%;"}
- .span6
+ %div
+ %div
= link_to project_issues_path(milestone.project, milestone_id: milestone.id) do
= pluralize milestone.issues.count, 'Issue'
&nbsp;
@@ -25,3 +24,5 @@
= pluralize milestone.merge_requests.count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
+ .progress.progress-info
+ .bar{style: "width: #{milestone.percent_complete}%;"}
diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml
index b78f17053fd..fb7cbc41edf 100644
--- a/app/views/milestones/index.html.haml
+++ b/app/views/milestones/index.html.haml
@@ -3,11 +3,14 @@
%h3.page_title
Milestones
- if can? current_user, :admin_milestone, @project
- = link_to "New Milestone", new_project_milestone_path(@project), class: "pull-right btn btn-small", title: "New Milestone"
+ = link_to new_project_milestone_path(@project), class: "pull-right btn btn-primary", title: "New Milestone" do
+ %i.icon-plus
+ New Milestone
%br
- %div.ui-box
- .title
- %ul.nav.nav-pills
+
+ .row
+ .span3
+ %ul.nav.nav-pills.nav-stacked
%li{class: ("active" if (params[:f] == "active" || !params[:f]))}
= link_to project_milestones_path(@project, f: "active") do
Active
@@ -17,12 +20,13 @@
%li{class: ("active" if params[:f] == "all")}
= link_to project_milestones_path(@project, f: "all") do
All
+ .span9
+ .ui-box
+ %ul.well-list
+ = render @milestones
- %ul.well-list
- = render @milestones
+ - if @milestones.blank?
+ %li
+ %h3.nothing_here_message Nothing to show here
- - if @milestones.present?
- %li.bottom= paginate @milestones, theme: "gitlab"
- - else
- %li
- %h3.nothing_here_message Nothing to show here
+ = paginate @milestones, theme: "gitlab"
diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml
index e1808a2003f..034c37852f1 100644
--- a/app/views/milestones/show.html.haml
+++ b/app/views/milestones/show.html.haml
@@ -1,3 +1,4 @@
+= render "issues/head"
.row
.span6
%h3.page_title
@@ -87,8 +88,6 @@
%h6 Participants:
%div
- @users.each do |user|
- = link_to user, class: 'float-link' do
- = user.avatar_image
- = user.name
+ = link_to_member(@project, user)
.clearfix
diff --git a/app/views/milestones/update.js.haml b/app/views/milestones/update.js.haml
new file mode 100644
index 00000000000..3ff84915e97
--- /dev/null
+++ b/app/views/milestones/update.js.haml
@@ -0,0 +1,2 @@
+:plain
+ $('##{dom_id(@milestone)}').fadeOut();
diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml
index c2bdeafb830..7add2921830 100644
--- a/app/views/notes/_form.html.haml
+++ b/app/views/notes/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note js-new-note-form" } do |f|
+= form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note js-new-note-form common-note-form" } do |f|
= note_target_fields
= f.hidden_field :commit_id
@@ -27,15 +27,6 @@
%a.btn.grouped.js-close-discussion-note-form Cancel
.note-form-option
- = label_tag :notify do
- = check_box_tag :notify, 1, false
- %span.light Notify team via email
-
- .js-notify-commit-author
- = label_tag :notify_author do
- = check_box_tag :notify_author, 1 , false
- %span.light Notify commit author
- .note-form-option
%a.choose-btn.btn.btn-small.js-choose-note-attachment-button
%i.icon-paper-clip
%span Choose File ...
diff --git a/app/views/notes/_notes_with_form.html.haml b/app/views/notes/_notes_with_form.html.haml
index 2566edd81ad..38d1a3c93c0 100644
--- a/app/views/notes/_notes_with_form.html.haml
+++ b/app/views/notes/_notes_with_form.html.haml
@@ -6,6 +6,4 @@
= render "notes/form"
:javascript
- $(function(){
- NoteList.init("#{@target_id}", "#{@target_type}", "#{project_notes_path(@project)}");
- });
+ NoteList.init("#{@target_id}", "#{@target_type}", "#{project_notes_path(@project)}");
diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml
new file mode 100644
index 00000000000..b7f39306fd8
--- /dev/null
+++ b/app/views/notifications/show.html.haml
@@ -0,0 +1,77 @@
+%h3.page_title Setup your notification level
+
+%br
+
+%p.light
+ %strong Disabled
+ &ndash; You will not get any notifications via email
+%p.light
+ %strong Participating
+ &ndash; You will receive only notifications from related resources(ex. from assigned issue or your commit)
+%p.light
+ %strong Watch
+ &ndash; You will receive all notifications from projects in which you participate
+%hr
+
+.row
+ .span4
+ %h5 Global setting
+ .span7
+ = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
+ = hidden_field_tag :notification_type, 'global'
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled?, class: 'trigger-submit'
+ %span Disabled
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating?, class: 'trigger-submit'
+ %span Participating
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit'
+ %span Watch
+
+%hr
+= link_to '#', class: 'js-toggle-visibility-link' do
+ %h6.btn.btn-tiny
+ %i.icon-chevron-down
+ %span Per project notifications setting
+
+%ul.well-list.js-toggle-visibility-container.hide
+ - @users_projects.each do |users_project|
+ - notification = Notification.new(users_project)
+ %li
+ .row
+ .span4
+ %span
+ = link_to_project(users_project.project)
+ .span7
+ = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
+ = hidden_field_tag :notification_type, 'project', id: dom_id(users_project, 'notification_type')
+ = hidden_field_tag :notification_id, users_project.id, id: dom_id(users_project, 'notification_id')
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit'
+ %span Use global setting
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit'
+ %span Disabled
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_PARTICIPATING, notification.participating?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit'
+ %span Participating
+
+ = label_tag do
+ = radio_button_tag :notification_level, Notification::N_WATCH, notification.watch?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit'
+ %span Watch
+
+
+.save-status-fixed
+ %span.update-success.cgreen.hide
+ %i.icon-ok
+ Saved
+ %span.update-failed.cred.hide
+ %i.icon-remove
+ Failed
diff --git a/app/views/notifications/update.js.haml b/app/views/notifications/update.js.haml
new file mode 100644
index 00000000000..88e74d50671
--- /dev/null
+++ b/app/views/notifications/update.js.haml
@@ -0,0 +1,6 @@
+- if @saved
+ :plain
+ $('.save-status-fixed .update-success').showAndHide();
+- else
+ :plain
+ $('.save-status-fixed .update-failed').showAndHide();
diff --git a/app/views/notify/closed_issue_email.html.haml b/app/views/notify/closed_issue_email.html.haml
new file mode 100644
index 00000000000..23ccc4538de
--- /dev/null
+++ b/app/views/notify/closed_issue_email.html.haml
@@ -0,0 +1,5 @@
+%p
+ = "Issue was closed by #{@updated_by.name}"
+%p
+ = "Issue ##{@issue.id}"
+ = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title
diff --git a/app/views/notify/closed_issue_email.text.haml b/app/views/notify/closed_issue_email.text.haml
new file mode 100644
index 00000000000..0cca321552c
--- /dev/null
+++ b/app/views/notify/closed_issue_email.text.haml
@@ -0,0 +1,3 @@
+= "Issue was closed by #{@updated_by.name}"
+
+Issue ##{@issue.id}: #{project_issue_url(@issue.project, @issue)}
diff --git a/app/views/notify/closed_merge_request_email.html.haml b/app/views/notify/closed_merge_request_email.html.haml
new file mode 100644
index 00000000000..0c6c79e097a
--- /dev/null
+++ b/app/views/notify/closed_merge_request_email.html.haml
@@ -0,0 +1,9 @@
+%p
+ = "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}"
+%p
+ = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request)
+%p
+ Branches: #{@merge_request.source_branch} &rarr; #{@merge_request.target_branch}
+%p
+ Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
+
diff --git a/app/views/notify/closed_merge_request_email.text.haml b/app/views/notify/closed_merge_request_email.text.haml
new file mode 100644
index 00000000000..ee4648e3d09
--- /dev/null
+++ b/app/views/notify/closed_merge_request_email.text.haml
@@ -0,0 +1,8 @@
+= "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}"
+
+Merge Request url: #{project_merge_request_url(@merge_request.project, @merge_request)}
+
+Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch}
+
+Author: #{@merge_request.author_name}
+Assignee: #{@merge_request.assignee_name}
diff --git a/app/views/notify/merged_merge_request_email.html.haml b/app/views/notify/merged_merge_request_email.html.haml
new file mode 100644
index 00000000000..2b8cc030b23
--- /dev/null
+++ b/app/views/notify/merged_merge_request_email.html.haml
@@ -0,0 +1,9 @@
+%p
+ = "Merge Request #{@merge_request.id} was merged"
+%p
+ = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request)
+%p
+ Branches: #{@merge_request.source_branch} &rarr; #{@merge_request.target_branch}
+%p
+ Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
+
diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml
new file mode 100644
index 00000000000..91c23360195
--- /dev/null
+++ b/app/views/notify/merged_merge_request_email.text.haml
@@ -0,0 +1,8 @@
+= "Merge Request #{@merge_request.id} was merged"
+
+Merge Request Url: #{project_merge_request_url(@merge_request.project, @merge_request)}
+
+Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch}
+
+Author: #{@merge_request.author_name}
+Assignee: #{@merge_request.assignee_name}
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index 0c891748918..f11c850641b 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,9 @@
%p
- New Issue was created and assigned to you.
+ New Issue was created.
%p
= "Issue ##{@issue.id}"
= link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title
+%p
+ Author: #{@issue.author_name}
+%p
+ Assignee: #{@issue.assignee_name}
diff --git a/app/views/notify/new_issue_email.text.erb b/app/views/notify/new_issue_email.text.erb
index 5ed55c35b23..9907ca83247 100644
--- a/app/views/notify/new_issue_email.text.erb
+++ b/app/views/notify/new_issue_email.text.erb
@@ -1,4 +1,5 @@
-New Issue was created and assigned to you.
+New Issue was created.
-
Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
+Author: <%= @issue.author_name %>
+Asignee: <%= @issue.assignee_name %>
diff --git a/app/views/notify/new_ssh_key_email.html.haml b/app/views/notify/new_ssh_key_email.html.haml
index 57f4297e6cb..eff197ce0f4 100644
--- a/app/views/notify/new_ssh_key_email.html.haml
+++ b/app/views/notify/new_ssh_key_email.html.haml
@@ -6,5 +6,5 @@
title:
%code= @key.title
%p
- If this key was added in error, you can remove here:
+ If this key was added in error, you can remove it here:
= link_to "SSH Keys", keys_url
diff --git a/app/views/notify/new_ssh_key_email.text.erb b/app/views/notify/new_ssh_key_email.text.erb
index 71974eab975..2b1f8a06858 100644
--- a/app/views/notify/new_ssh_key_email.text.erb
+++ b/app/views/notify/new_ssh_key_email.text.erb
@@ -4,4 +4,4 @@ A new public key was added to your account:
title.................. <%= @key.title %>
-If this key was added in error, you can remove here: <%= keys_url %>
+If this key was added in error, you can remove it here: <%= keys_url %>
diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml
index 8606dc6aa76..9804fbdd51e 100644
--- a/app/views/notify/new_user_email.html.haml
+++ b/app/views/notify/new_user_email.html.haml
@@ -2,9 +2,9 @@
Hi #{@user['name']}!
%p
- if Gitlab.config.gitlab.signup_enabled
- Account has been created successfully.
+ Your account has been created successfully.
- else
- Administrator created account for you. Now you are a member of company GitLab application.
+ The Administrator created an account for you. Now you are a member of company GitLab application.
%p
login..........................................
%code= @user['email']
@@ -12,5 +12,9 @@
- unless Gitlab.config.gitlab.signup_enabled
password..................................
%code= @password
+
+%p
+ Please change your password immediately after login.
+
%p
= link_to "Click here to login", root_url
diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb
index 94072d7fe5c..777930a2803 100644
--- a/app/views/notify/new_user_email.text.erb
+++ b/app/views/notify/new_user_email.text.erb
@@ -1,10 +1,12 @@
Hi <%= @user.name %>!
-
-Administrator created account for you. Now you are a member of company GitLab application.
-
+
+The Administrator created an account for you. Now you are a member of company GitLab application.
+
login.................. <%= @user.email %>
<% unless Gitlab.config.gitlab.signup_enabled %>
password............... <%= @password %>
<% end %>
+Please change your password immediately after login.
+
Click here to login: <%= url_for(root_url) %>
diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml
index b20d5c7a6a1..09d9ec10e81 100644
--- a/app/views/profiles/account.html.haml
+++ b/app/views/profiles/account.html.haml
@@ -1,11 +1,35 @@
-- if Gitlab.config.omniauth.enabled
- %fieldset
- %legend Social Accounts
- .oauth_select_holder
- %p.hint Tip: Click on icon to activate sigin with one of the following services
- - User.omniauth_providers.each do |provider|
- %span{class: oauth_active_class(provider) }
- = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
+- unless current_user.ldap_user?
+ - if Gitlab.config.omniauth.enabled
+ %fieldset
+ %legend Social Accounts
+ .oauth_select_holder
+ %p.hint Tip: Click on icon to activate sigin with one of the following services
+ - enabled_social_providers.each do |provider|
+ %span{class: oauth_active_class(provider) }
+ = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
+
+
+ %fieldset.update-password
+ %legend Password
+ = form_for @user, url: update_password_profile_path, method: :put do |f|
+ .padded
+ %p.slead After successful password update you will be redirected to login page where you should login with new password
+ -if @user.errors.any?
+ .alert.alert-error
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
+
+ .clearfix
+ = f.label :password
+ .input= f.password_field :password, required: true
+ .clearfix
+ = f.label :password_confirmation
+ .input
+ = f.password_field :password_confirmation, required: true
+ .clearfix
+ .input
+ = f.submit 'Save password', class: "btn btn-save"
@@ -29,29 +53,6 @@
%span You don`t have one yet. Click generate to fix it.
= f.submit 'Generate', class: "btn success btn-build-token"
-%fieldset.update-password
- %legend Password
- = form_for @user, url: update_password_profile_path, method: :put do |f|
- .padded
- %p.slead After successful password update you will be redirected to login page where you should login with new password
- -if @user.errors.any?
- .alert.alert-error
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
-
- .clearfix
- = f.label :password
- .input= f.password_field :password, required: true
- .clearfix
- = f.label :password_confirmation
- .input
- = f.password_field :password_confirmation, required: true
- .clearfix
- .input
- = f.submit 'Save password', class: "btn btn-save"
-
-
- if current_user.can_change_username?
%fieldset.update-username
@@ -78,7 +79,7 @@
.input
= f.submit 'Save username', class: "btn btn-save"
-- if Gitlab.config.gitlab.signup_enabled
+- if gitlab_config.signup_enabled
%fieldset.remove-account
%legend
Remove account
diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml
index 77068dabb32..878297fe49d 100644
--- a/app/views/profiles/design.html.haml
+++ b/app/views/profiles/design.html.haml
@@ -55,3 +55,8 @@
= image_tag "solarized_dark.png"
= f.radio_button :color_scheme_id, 3
Solarized Dark
+ = label_tag do
+ .prev
+ = image_tag "monokai.png"
+ = f.radio_button :color_scheme_id, 4
+ Monokai
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 9cab3ba5252..d4793da8987 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -51,7 +51,7 @@
%legend Tips:
%ul
%li
- %p You can change your password on Account page
+ %p You can change your password on the Account page
- if Gitlab.config.gravatar.enabled
%li
%p You can change your avatar at #{link_to "gravatar.com", "http://gravatar.com"}
@@ -73,16 +73,17 @@
Want to share a team between projects?
= link_to new_team_path, class: "btn btn-tiny" do
Create a team
- %fieldset
- %legend
- Personal projects:
- %small.pull-right
- %span= current_user.owned_projects.count
- of
- %span= current_user.projects_limit
- .padded
- .progress
- .bar{style: "width: #{current_user.projects_limit_percent}%;"}
+ - unless current_user.projects_limit_left > 100
+ %fieldset
+ %legend
+ Owned projects:
+ %small.pull-right
+ %span= current_user.owned_projects.count
+ of
+ %span= current_user.projects_limit
+ .padded
+ .progress
+ .bar{style: "width: #{current_user.projects_limit_percent}%;"}
%fieldset
%legend
diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml
index e52df19be96..f8276c3c2b6 100644
--- a/app/views/projects/_clone_panel.html.haml
+++ b/app/views/projects/_clone_panel.html.haml
@@ -1,17 +1,24 @@
.project_clone_panel
.row
- .span7
+ .span8
.form-horizontal= render "shared/clone_panel"
- .span4.pull-right
+ .span3.pull-right
.pull-right
- unless @project.empty_repo?
+ - if can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
+ - if current_user.already_forked?(@project)
+ = link_to project_path(current_user.fork_of(@project)), class: 'btn grouped btn-primary' do
+ Forked
+ - else
+ = link_to fork_project_path(@project), title: "Fork", class: "btn grouped", method: "POST" do
+ %i.icon-copy
+ Fork
- if can? current_user, :download_code, @project
- = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do
+ = link_to archive_project_repository_path(@project), class: "btn grouped" do
%i.icon-download-alt
Download
- - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
- = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn-small btn grouped" do
- Merge Request
- - if @project.issues_enabled && can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), title: "New Issue", class: "btn-small btn grouped" do
- Issue
+
+ = link_to tags_project_repository_path(@project), class: "btn grouped only-wide", title: 'Git Tags' do
+ %i.icon-tags
+ Tags
+
diff --git a/app/views/projects/_errors.html.haml b/app/views/projects/_errors.html.haml
new file mode 100644
index 00000000000..bb9759353a3
--- /dev/null
+++ b/app/views/projects/_errors.html.haml
@@ -0,0 +1,4 @@
+- if @project.errors.any?
+ .alert.alert-error
+ %button{ type: "button", class: "close", "data-dismiss" => "alert"} &times;
+ = @project.errors.full_messages.first
diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml
deleted file mode 100644
index 6d547c94e98..00000000000
--- a/app/views/projects/_form.html.haml
+++ /dev/null
@@ -1,139 +0,0 @@
-.row
- .span3
- %ul.nav.nav-pills.nav-stacked
- %li.active
- = link_to 'Settings', '#tab-settings', 'data-toggle' => 'tab'
- %li
- = link_to 'Transfer', '#tab-transfer', 'data-toggle' => 'tab'
- %li
- = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab'
-
- .span9
- .tab-content
- .tab-pane.active#tab-settings
- .ui-box.white
- %h5.title Settings:
- .form-holder
- = form_for(@project, remote: true) do |f|
- - if @project.errors.any?
- .alert.alert-error
- %ul
- - @project.errors.full_messages.each do |msg|
- %li= msg
-
- %fieldset
- .clearfix.project_name_holder
- = f.label :name do
- Project name is
- .input
- = f.text_field :name, placeholder: "Example Project", class: "span5"
-
-
- .clearfix
- = f.label :description do
- Project description
- %span.light (optional)
- .input
- = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250
-
- - unless @repository.heads.empty?
- .clearfix
- = f.label :default_branch, "Default Branch"
- .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;")
-
-
- - if can?(current_user, :change_public_mode, @project)
- %fieldset.public-mode
- %legend
- Public mode:
- .control-group
- = f.label :public, class: 'control-label' do
- %span Public clone access
- .controls
- = f.check_box :public
- %span.descr
- If checked, this project can be cloned
- %em without any
- authentification.
- It will also be listed on the #{link_to "public access directory", public_root_path}.
-
- %fieldset.features
- %legend
- Features:
- .control-group
- = f.label :issues_enabled, "Issues", class: 'control-label'
- .controls
- = f.check_box :issues_enabled
- %span.descr Lightweight issue tracking system for this project
-
- - if Project.issues_tracker.values.count > 1
- .control-group
- = f.label :issues_tracker, "Issues tracker", class: 'control-label'
- .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
-
- .clearfix
- = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
- .input= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?
-
- .control-group
- = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
- .controls
- = f.check_box :merge_requests_enabled
- %span.descr Submit changes to be merged upstream.
-
- .control-group
- = f.label :wiki_enabled, "Wiki", class: 'control-label'
- .controls
- = f.check_box :wiki_enabled
- %span.descr Pages for project documentation
-
- .control-group
- = f.label :wall_enabled, "Wall", class: 'control-label'
- .controls
- = f.check_box :wall_enabled
- %span.descr Simple chat system for broadcasting inside project
-
- .control-group
- = f.label :snippets_enabled, "Snippets", class: 'control-label'
- .controls
- = f.check_box :snippets_enabled
- %span.descr Share code pastes with others out of git repository
-
-
- .form-actions
- = f.submit 'Save', class: "btn btn-save"
-
- .tab-pane#tab-transfer
- - if can?(current_user, :change_namespace, @project)
- .ui-box.ui-box-danger
- %h5.title Transfer project
- .form-holder
- = form_for(@project, remote: true, html: { class: 'transfer-project' }) do |f|
- .control-group
- = f.label :namespace_id do
- %span Namespace
- .controls
- .clearfix
- = f.select :namespace_id, namespaces_options(@project.namespace_id || Namespace::global_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'}
- %ul
- %li Be careful. Changing project namespace can have unintended side effects
- %li You can transfer project only to namespaces you can manage
- %li You will need to update your local repositories to point to the new location.
- .form-actions
- = f.submit 'Transfer', class: "btn btn-remove"
- - else
- %p.nothing_here_message Only project owner can transfer a project
-
- .tab-pane#tab-remove
- - if can?(current_user, :remove_project, @project)
- .ui-box.ui-box-danger
- %h5.title Remove project
- .ui-box-body
- %p
- Remove of project will cause removing repository and all related resources like issues, merge requests etc.
- %p
- %strong Removed project can not be restored!
-
- = link_to 'Remove project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small"
- - else
- %p.nothing_here_message Only project owner can remove a project
diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml
deleted file mode 100644
index b6503636890..00000000000
--- a/app/views/projects/_new_form.html.haml
+++ /dev/null
@@ -1,48 +0,0 @@
-= form_for(@project, remote: true) do |f|
- - if @project.errors.any?
- .alert.alert-error
- %span= @project.errors.full_messages.first
- .clearfix.project_name_holder
- = f.label :name do
- Project name is
- .input
- = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
- = f.submit 'Create project', class: "btn btn-create project-submit"
-
- - if current_user.can_select_namespace?
- .clearfix
- = f.label :namespace_id do
- %span Namespace
- .input
- = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'}
-
-
- .clearfix
- .input
- = link_to "#", class: 'appear-link' do
- %i.icon-upload-alt
- %span Import existing repository?
- .clearfix.appear-data
- = f.label :import_url do
- %span Import existing repo
- .input
- = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git'
- .light
- URL must be clonable
-
- %p.padded
- New projects are private by default. You choose who can see the project and commit to repository.
- %hr
-
- - if current_user.can_create_group?
- .clearfix
- .input.light
- Need a group for several dependent projects?
- = link_to new_group_path, class: "btn btn-tiny" do
- Create a group
- - if current_user.can_create_team?
- .clearfix
- .input.light
- Want to share a project between team?
- = link_to new_team_path, class: "btn btn-tiny" do
- Create a team
diff --git a/app/views/projects/create.js.haml b/app/views/projects/create.js.haml
index 296c8688f47..52e61f47283 100644
--- a/app/views/projects/create.js.haml
+++ b/app/views/projects/create.js.haml
@@ -3,8 +3,6 @@
location.href = "#{project_path(@project)}";
- else
:plain
- $('.project_new_holder').show();
- $("#new_project").replaceWith("#{escape_javascript(render('new_form'))}");
+ $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
$('.save-project-loader').hide();
- new Projects();
- $('select.chosen').chosen()
+ $('.project-edit-container').show();
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 394522bfd88..bec64bf6c58 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -1,13 +1,177 @@
= render "projects/settings_nav"
-.project_edit_holder
+.project-edit-container
%h3.page_title Edit Project
%hr
- = render "projects/form"
-%div.save-project-loader.hide
+ .project-edit-errors
+ .project-edit-content
+ .row
+ .span3
+ %ul.nav.nav-pills.nav-stacked
+ %li.active
+ = link_to 'Settings', '#tab-settings', 'data-toggle' => 'tab'
+ %li
+ = link_to 'Rename repo', '#tab-rename', 'data-toggle' => 'tab'
+ %li
+ = link_to 'Transfer', '#tab-transfer', 'data-toggle' => 'tab'
+ %li
+ = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab'
+
+ .span9
+ .tab-content
+ .tab-pane.active#tab-settings
+ .ui-box.white
+ %h5.title Settings:
+ .form-holder
+ = form_for(@project, remote: true) do |f|
+ %fieldset
+ .clearfix.project_name_holder
+ = f.label :name do
+ Project name is
+ .input
+ = f.text_field :name, placeholder: "Example Project", class: "span5"
+
+
+ .clearfix
+ = f.label :description do
+ Project description
+ %span.light (optional)
+ .input
+ = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250
+
+ - unless @project.empty_repo?
+ .clearfix
+ = f.label :default_branch, "Default Branch"
+ .input= f.select(:default_branch, @repository.branch_names, {}, {class: 'chosen'})
+
+
+ - if can?(current_user, :change_public_mode, @project)
+ %fieldset.public-mode
+ %legend
+ Public mode:
+ .control-group
+ = f.label :public, class: 'control-label' do
+ %span Public access
+ .controls
+ = f.check_box :public
+ %span.descr
+ If checked, this project can be cloned
+ %em without any
+ authentication.
+ It will also be listed on the #{link_to "public access directory", public_root_path}.
+ %em Any
+ user will have #{link_to "Guest", help_permissions_path} permissions on the repository.
+
+ %fieldset.features
+ %legend
+ Labels:
+ .control-group
+ = f.label :label_list, "Labels", class: 'control-label'
+ .controls
+ = f.text_field :label_list, maxlength: 2000, class: "span5"
+ %p.hint Separate with comma.
+
+ %fieldset.features
+ %legend
+ Features:
+ .control-group
+ = f.label :issues_enabled, "Issues", class: 'control-label'
+ .controls
+ = f.check_box :issues_enabled
+ %span.descr Lightweight issue tracking system for this project
+
+ - if Project.issues_tracker.values.count > 1
+ .control-group
+ = f.label :issues_tracker, "Issues tracker", class: 'control-label'
+ .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
+
+ .clearfix
+ = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
+ .input= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?
+
+ .control-group
+ = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
+ .controls
+ = f.check_box :merge_requests_enabled
+ %span.descr Submit changes to be merged upstream.
+
+ .control-group
+ = f.label :wiki_enabled, "Wiki", class: 'control-label'
+ .controls
+ = f.check_box :wiki_enabled
+ %span.descr Pages for project documentation
+
+ .control-group
+ = f.label :wall_enabled, "Wall", class: 'control-label'
+ .controls
+ = f.check_box :wall_enabled
+ %span.descr Simple chat system for broadcasting inside project
+
+ .control-group
+ = f.label :snippets_enabled, "Snippets", class: 'control-label'
+ .controls
+ = f.check_box :snippets_enabled
+ %span.descr Share code pastes with others out of git repository
+
+
+ .form-actions
+ = f.submit 'Save', class: "btn btn-save"
+
+ .tab-pane#tab-transfer
+ - if can?(current_user, :change_namespace, @project)
+ .ui-box.ui-box-danger
+ %h5.title Transfer project
+ .errors-holder
+ .form-holder
+ = form_for(@project, url: transfer_project_path(@project), remote: true, html: { class: 'transfer-project' }) do |f|
+ .control-group
+ = f.label :namespace_id do
+ %span Namespace
+ .controls
+ .clearfix
+ = f.select :namespace_id, namespaces_options(@project.namespace_id || Namespace::global_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'}
+ %ul
+ %li Be careful. Changing project namespace can have unintended side effects
+ %li You can transfer project only to namespaces you can manage
+ %li You will need to update your local repositories to point to the new location.
+ .form-actions
+ = f.submit 'Transfer', class: "btn btn-remove"
+ - else
+ %p.nothing_here_message Only project owner can transfer a project
+
+ .tab-pane#tab-rename
+ .ui-box.ui-box-danger
+ %h5.title Rename repository
+ .errors-holder
+ .form-holder
+ = form_for(@project) do |f|
+ .control-group
+ = f.label :path do
+ %span Path
+ .controls
+ .clearfix
+ = f.text_field :path
+ %ul
+ %li Be careful. Rename of project repo can have unintended side effects
+ %li You will need to update your local repositories to point to the new location.
+ .form-actions
+ = f.submit 'Rename', class: "btn btn-remove"
+
+ .tab-pane#tab-remove
+ - if can?(current_user, :remove_project, @project)
+ .ui-box.ui-box-danger
+ %h5.title Remove project
+ .ui-box-body
+ %p
+ Remove of project will cause removing repository and all related resources like issues, merge requests etc.
+ %p
+ %strong Removed project can not be restored!
+
+ = link_to 'Remove project', @project, confirm: remove_project_message(@project), method: :delete, class: "btn btn-remove btn-small"
+ - else
+ %p.nothing_here_message Only project owner can remove a project
+
+.save-project-loader.hide
%center
= image_tag "ajax_loader.gif"
- %h3 Saving project. Please wait a few minutes
-
-:javascript
- $(function(){ new Projects(); });
+ %h3 Saving project. Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index b1795b301b0..56dbbf0755e 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -31,4 +31,4 @@
- if can? current_user, :remove_project, @project
.prepend-top-20
- = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove pull-right"
+ = link_to 'Remove project', @project, confirm: remove_project_message(@project), method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 933cb671142..e9099f264bc 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -1,12 +1,55 @@
-.project_new_holder
- %h3.page_title
- New Project
+.project-edit-container
+ %h3.page_title New Project
%hr
- = render 'new_form'
-%div.save-project-loader.hide
+ .project-edit-errors
+ = render 'projects/errors'
+ .project-edit-content
+ = form_for @project, remote: true do |f|
+ .clearfix.project_name_holder
+ = f.label :name do
+ Project name is
+ .input
+ = f.text_field :name, placeholder: "Example Project", class: "xxlarge", tabindex: 1
+ = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 3
+
+ - if current_user.can_select_namespace?
+ .clearfix
+ = f.label :namespace_id do
+ %span Namespace
+ .input
+ = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen', tabindex: 2}
+
+ .clearfix
+ .input
+ = link_to "#", class: 'appear-link' do
+ %i.icon-upload-alt
+ %span Import existing repository?
+ .clearfix.appear-data.import-url-data
+ = f.label :import_url do
+ %span Import existing repo
+ .input
+ = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git'
+ .light
+ URL must be clonable
+
+ %p.padded
+ New projects are private by default. You choose who can see the project and commit to repository.
+ %hr
+
+ - if current_user.can_create_group?
+ .clearfix
+ .input.light
+ Need a group for several dependent projects?
+ = link_to new_group_path, class: "btn btn-tiny" do
+ Create a group
+ - if current_user.can_create_team?
+ .clearfix
+ .input.light
+ Want to share a project between team?
+ = link_to new_team_path, class: "btn btn-tiny" do
+ Create a team
+
+.save-project-loader.hide
%center
= image_tag "ajax_loader.gif"
- %h3 Creating project &amp; repository. Please wait a few minutes
-
-:javascript
- $(function(){ new Projects(); });
+ %h3 Creating project &amp; repository. Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 824d4daf698..f72ef0a99ae 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,32 +1,51 @@
= render 'clone_panel'
-= render "events/event_last_push", event: @last_push
.row
.span9
- .content_list= render @events
+ = render "events/event_last_push", event: @last_push
+ .content_list
.loading.hide
.span3
- .ui-box.white
- .padded
- %h3.page_title
- = @project.name
- - if @project.description.present?
- %p.light= @project.description
+ .light-well
+ .dropdown.pull-right
+ %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-plus-sign-alt
+ %b.caret
+ %ul.dropdown-menu
+ - if @project.issues_enabled && can?(current_user, :write_issue, @project)
+ %li
+ = link_to url_for_new_issue, title: "New Issue" do
+ Issue
+ - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
+ %li
+ = link_to new_project_merge_request_path(@project), title: "New Merge Request" do
+ Merge Request
+ - if @project.snippets_enabled && can?(current_user, :write_snippet, @project)
+ %li
+ = link_to new_project_snippet_path(@project), title: "New Snippet" do
+ Snippet
+ - if can?(current_user, :admin_team_member, @project)
+ %li.divider
+ %li
+ = link_to new_project_team_member_path(@project), title: "New Team member" do
+ Team member
- %hr
+ %h3.page_title
+ = @project.name
+ - if @project.description.present?
+ %p.light= @project.description
+
+ %hr
+ %p
+ %p Repo Size: #{@project.repository.size} MB
+ %p Created on: #{@project.created_at.stamp('Aug 22, 2013')}
+ %p Owner: #{link_to @project.owner_name, @project.owner}
+ - if @project.forked_from_project
%p
- Access level:
- - if @project.public
- %span.cblue
- %i.icon-share
- Public
- - else
- %span.cgreen
- %i.icon-lock
- Private
+ Forked from:
+ = link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
- %p Repo Size: #{@project.repository.size} MB
- %p Created at: #{@project.created_at.stamp('Aug 22, 2013')}
- %p Owner: #{link_to @project.owner_name, @project.owner}
-:javascript
- $(function(){ Pager.init(20); });
+ - if @project.gitlab_ci?
+ %hr
+ = link_to @project.gitlab_ci_service.builds_path do
+ = image_tag @project.gitlab_ci_service.status_img_path, alt: "build status"
diff --git a/app/views/projects/transfer.js.haml b/app/views/projects/transfer.js.haml
new file mode 100644
index 00000000000..10b0de98c04
--- /dev/null
+++ b/app/views/projects/transfer.js.haml
@@ -0,0 +1,7 @@
+- if @project.errors[:namespace_id].present?
+ :plain
+ $("#tab-transfer .errors-holder").replaceWith(errorMessage('#{escape_javascript(@project.errors[:namespace_id].first)}'));
+ $("#tab-transfer .form-actions input").removeAttr('disabled').removeClass('disabled');
+- else
+ :plain
+ location.href = "#{edit_project_path(@project)}";
diff --git a/app/views/projects/tree.js.haml b/app/views/projects/tree.js.haml
deleted file mode 100644
index ba5d53c16a2..00000000000
--- a/app/views/projects/tree.js.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-:plain
- $("#tree-holder table").hide("slide", { direction: "left" }, 150, function(){
- $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}");
- $("#tree-holder table").show("slide", { direction: "right" }, 150);
- });
diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml
index f44ed529182..cbb21f2b9fb 100644
--- a/app/views/projects/update.js.haml
+++ b/app/views/projects/update.js.haml
@@ -3,6 +3,7 @@
location.href = "#{edit_project_path(@project)}";
- else
:plain
- $('.project_edit_holder').show();
- $(".edit_project").replaceWith("#{escape_javascript(render('form'))}");
+ $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
$('.save-project-loader').hide();
+ $('.project-edit-container').show();
+ $('.project-edit-content .btn-save').enableButton();
diff --git a/app/views/projects/update_failed.js.haml b/app/views/projects/update_failed.js.haml
deleted file mode 100644
index a3ac5f4088f..00000000000
--- a/app/views/projects/update_failed.js.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-:plain
- $(".save-project-loader").replaceWith(errorMessage('#{escape_javascript(@error.message)}'));
diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml
index 15644de552f..a338344c52d 100644
--- a/app/views/protected_branches/index.html.haml
+++ b/app/views/protected_branches/index.html.haml
@@ -51,4 +51,4 @@
(branch was removed from repository)
%td
- if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small"
+ = link_to 'Unprotect', [@project, branch], confirm: 'Branch will be writable for developers. Are you sure?', method: :delete, class: "btn btn-remove btn-small"
diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml
index b50484f6354..e2b19d0d824 100644
--- a/app/views/public/projects/index.html.haml
+++ b/app/views/public/projects/index.html.haml
@@ -1,6 +1,16 @@
-%h3.page_title
- Projects (#{@projects.total_count})
- %small with read-only access
+.row
+ .span6
+ %h3.page_title
+ Projects (#{@projects.total_count})
+ %small with read-only access
+ .span6
+ .pull-right
+ = form_tag public_projects_path, method: :get, class: 'form-inline' do |f|
+ .search-holder
+ .input
+ = search_field_tag :search, params[:search], placeholder: "gitlab-ci", class: "span3 search-text-input", id: "projects_search"
+ = submit_tag 'Search', class: "btn btn-primary wide"
+
%hr
.public-projects
@@ -9,7 +19,10 @@
%li.clearfix
%h5
%i.icon-share
- = project.name_with_namespace
+ - if current_user
+ = link_to_project project
+ - else
+ = project.name_with_namespace
.pull-right
%pre.dark.tiny git clone #{project.http_url_to_repo}
%p.description
@@ -17,4 +30,4 @@
- unless @projects.present?
%h3.nothing_here_message No public projects
- = paginate @projects, theme: "admin"
+ = paginate @projects, theme: "gitlab"
diff --git a/app/views/refs/logs_tree.js.haml b/app/views/refs/logs_tree.js.haml
index 23a6dae7810..0b517327139 100644
--- a/app/views/refs/logs_tree.js.haml
+++ b/app/views/refs/logs_tree.js.haml
@@ -1,4 +1,4 @@
-- @logs.each do |content_data|
+- @logs.each do |content_data|
- file_name = content_data[:file_name]
- commit = content_data[:commit]
diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml
index a6faa5fd633..dd91e14b66b 100644
--- a/app/views/repositories/_branch.html.haml
+++ b/app/views/repositories/_branch.html.haml
@@ -1,5 +1,4 @@
-- commit = Commit.new(branch.commit)
-- commit = CommitDecorator.decorate(commit)
+- commit = Commit.new(Gitlab::Git::Commit.new(branch.commit))
%tr
%td
= link_to project_commits_path(@project, branch.name) do
diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml
index eaf15ca77d6..6bb75265ffb 100644
--- a/app/views/repositories/_feed.html.haml
+++ b/app/views/repositories/_feed.html.haml
@@ -1,5 +1,4 @@
- commit = update
-- commit = CommitDecorator.new(commit)
%tr
%td
= link_to project_commits_path(@project, commit.head.name) do
diff --git a/app/views/repositories/stats.html.haml b/app/views/repositories/stats.html.haml
index dde35ea38aa..6d1fb4686ea 100644
--- a/app/views/repositories/stats.html.haml
+++ b/app/views/repositories/stats.html.haml
@@ -1,8 +1,8 @@
= render "commits/head"
.row
- .span5
- %h4
- Stats:
+ .span6
+ %div#activity-chart.chart
+ %hr
%p
%b Total commits:
%span= @stats.commits_count
@@ -13,9 +13,8 @@
%b Authors:
%span= @stats.authors_count
- %br
- %div#activity-chart
- .span7
+
+ .span6
%h4 Top 50 Committers:
%ol.styled
- @stats.authors[0...50].each do |author|
@@ -28,14 +27,7 @@
:javascript
- $(function(){
- var labels = [#{@graph.labels.to_json}];
- var commits = [#{@graph.commits.join(', ')}];
- var r = Raphael('activity-chart');
- r.text(160, 10, "Commit activity for last #{@graph.weeks} weeks").attr({ font: "13px sans-serif" });
- r.barchart(
- 10, 10, 400, 160,
- [commits],
- {colors:["#456"]}
- ).label(labels, true);
- })
+ var labels = [#{@graph.labels.to_json}];
+ var commits = [#{@graph.commits.join(', ')}];
+ var title = "Commit activity for last #{@graph.weeks} weeks";
+ Chart.init(labels, commits, title);
diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml
index d4b8bbe10d4..bef5cd0841b 100644
--- a/app/views/repositories/tags.html.haml
+++ b/app/views/repositories/tags.html.haml
@@ -1,33 +1,30 @@
= render "commits/head"
- unless @tags.empty?
- %table
- %thead
- %tr
- %th Name
- %th Last commit
- %th
+ %ul.bordered-list
- @tags.each do |tag|
- - commit = Commit.new(tag.commit)
- - commit = CommitDecorator.decorate(commit)
- %tr
- %td
- %strong
- = link_to project_commits_path(@project, tag.name), class: "" do
- %i.icon-tag
- = tag.name
- %small.light= truncate(tag.message || '', length: 70)
- %td
- = image_tag gravatar_icon(commit.author_email), class: "avatar s16"
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- %span.light
- = time_ago_in_words(commit.committed_date)
- ago
- %td
+ - commit = Commit.new(Gitlab::Git::Commit.new(tag.commit))
+ %li
+ %h5
+ = link_to project_commits_path(@project, tag.name), class: "" do
+ %i.icon-tag
+ = tag.name
+ %small
+ = truncate(tag.message || '', length: 70)
+ .pull-right
+ %span.light
+ = time_ago_in_words(commit.committed_date)
+ ago
+ %div.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"
+
- if can? current_user, :download_code, @project
- = link_to archive_project_repository_path(@project, ref: tag.name) do
- %i.icon-download-alt
- Download
+ .pull-right
+ = link_to archive_project_repository_path(@project, ref: tag.name) do
+ %i.icon-download-alt
+ Download
+
- else
%h3.nothing_here_message
diff --git a/app/views/search/_blob.html.haml b/app/views/search/_blob.html.haml
new file mode 100644
index 00000000000..39e71170706
--- /dev/null
+++ b/app/views/search/_blob.html.haml
@@ -0,0 +1,10 @@
+%li
+ .file_holder
+ .file_title
+ = link_to project_blob_path(@project, tree_join(blob.ref, blob.filename), :anchor => "L" + blob.startline.to_s) do
+ %i.icon-file
+ %strong
+ = blob.filename
+ .file_content.code.term
+ %div{class: user_color_scheme_class}
+ = raw blob.colorize( formatter: :gitlab, options: { first_line_number: blob.startline } )
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index a523fa254df..f7a00b23480 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -1,16 +1,35 @@
-%fieldset
- %legend Groups:
- .clearfix
- = select_tag 'group_id', options_from_collection_for_select(current_user.authorized_groups, :id, :name, params[:group_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen'
-
-
-%fieldset
- %legend Teams:
- .clearfix
- = select_tag 'team_id', options_from_collection_for_select(current_user.authorized_teams, :id, :name, params[:team_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen'
-
-%fieldset
- %legend Projects:
- .clearfix
- = select_tag 'project_id', options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace, params[:project_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen'
+.dropdown.inline
+ %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-tags
+ %span.light Group:
+ - if @group.present?
+ %strong= @group.name
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to search_path(group_id: nil) do
+ Any
+ - current_user.authorized_groups.sort_by(&:name).each do |group|
+ %li
+ = link_to search_path(group_id: group.id, search: params[:search]) do
+ = group.name
+.dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-tags
+ %span.light Project:
+ - if @project.present?
+ %strong= @project.name_with_namespace
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to search_path(project_id: nil) do
+ Any
+ - current_user.authorized_projects.sort_by(&:name_with_namespace).each do |project|
+ %li
+ = link_to search_path(project_id: project.id, search: params[:search]) do
+ = project.name_with_namespace
diff --git a/app/views/search/_result.html.haml b/app/views/search/_result.html.haml
index bfa46075baa..4d8caa5e70c 100644
--- a/app/views/search/_result.html.haml
+++ b/app/views/search/_result.html.haml
@@ -1,9 +1,19 @@
%fieldset
%legend
Search results
- %span.cgray (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count})
+ %span.cgray (#{@total_results})
+
+- if @project
+ %ul.nav.nav-pills
+ %li{class: ("active" if params[:search_code].present?)}
+ = link_to search_path(params.merge(search_code: true)) do
+ Repository Code
+ %li{class: ("active" if params[:search_code].blank?)}
+ = link_to search_path(params.merge(search_code: nil)) do
+ Everything else
+
.search_results
- %ul.well-list
+ %ul.bordered-list
- @projects.each do |project|
%li
project:
@@ -33,6 +43,11 @@
= truncate wiki_page.title, length: 50
%span.light (#{wiki_page.project.name_with_namespace})
+ - @blobs.each do |blob|
+ = render 'blob', blob: blob
+
+ = paginate @blobs, theme: 'gitlab'
+
:javascript
$(function() {
$(".search_results .term").highlight("#{escape_javascript(params[:search])}");
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 5914c22df6e..f9647377961 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -4,12 +4,13 @@
%span Looking for
.input
= search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search"
+ = hidden_field_tag :project_id, params[:project_id]
+ = hidden_field_tag :group_id, params[:group_id]
+ = hidden_field_tag :search_code, params[:search_code]
= submit_tag 'Search', class: "btn btn-primary wide"
- .clearfix
- .row
- .span3
- = render 'filter', f: f
- .span9
- .results
- - if params[:search].present?
- = render 'search/result'
+ .prepend-top-10
+ = render 'filter', f: f
+
+ .results.prepend-top-10
+ - if params[:search].present?
+ = render 'search/result'
diff --git a/app/views/services/_form.html.haml b/app/views/services/_form.html.haml
new file mode 100644
index 00000000000..ff6769531c4
--- /dev/null
+++ b/app/views/services/_form.html.haml
@@ -0,0 +1,48 @@
+%h3.page_title
+ - if @service.activated?
+ %span.cgreen
+ %i.icon-circle
+ - else
+ %span.cgray
+ %i.icon-circle-blank
+ = @service.title
+
+%p= @service.description
+
+.back_link
+ = link_to project_services_path(@project) do
+ &larr; to services
+
+%hr
+
+= form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put) do |f|
+ - if @service.errors.any?
+ .alert.alert-error
+ %ul
+ - @service.errors.full_messages.each do |msg|
+ %li= msg
+
+
+ .control-group
+ = f.label :active, "Active", class: "control-label"
+ .controls
+ = f.check_box :active
+
+ - @service.fields.each do |field|
+ - name = field[:name]
+ - type = field[:type]
+ - placeholder = field[:placeholder]
+
+ .control-group
+ = f.label name, class: "control-label"
+ .controls
+ - if type == 'text'
+ = f.text_field name, class: "input-xlarge", placeholder: placeholder
+ - elsif type == 'checkbox'
+ = f.check_box name
+
+ .form-actions
+ = f.submit 'Save', class: 'btn btn-save'
+ &nbsp;
+ - if @service.valid? && @service.activated?
+ = link_to 'Test settings', test_project_service_path(@project, @service.to_param), class: 'btn btn-small'
diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml
deleted file mode 100644
index dfde643849e..00000000000
--- a/app/views/services/_gitlab_ci.html.haml
+++ /dev/null
@@ -1,46 +0,0 @@
-%h3.page_title
- GitLab CI
- %small Continuous integration server from GitLab
- .pull-right
- - if @service.active
- %small.cgreen Enabled
- - else
- %small.cgray Disabled
-
-
-
-.back_link
- = link_to project_services_path(@project) do
- &larr; to services
-
-%hr
-= form_for(@service, :as => :service, :url => project_service_path(@project, :gitlab_ci), :method => :put) do |f|
- - if @service.errors.any?
- .alert.alert-error
- %ul
- - @service.errors.full_messages.each do |msg|
- %li= msg
-
-
- .control-group
- = f.label :active, "Active", class: "control-label"
- .controls
- = f.check_box :active
-
- .control-group
- = f.label :project_url, "Project URL", class: "control-label"
- .controls
- = f.text_field :project_url, class: "input-xlarge", placeholder: "http://ci.gitlabhq.com/projects/3"
-
- .control-group
- = f.label :token, class: "control-label" do
- CI Project token
- .controls
- = f.text_field :token, class: "input-xlarge", placeholder: "GitLab CI project specific token"
-
-
- .form-actions
- = f.submit 'Save', class: 'btn btn-save'
- &nbsp;
- - if @service.valid? && @service.active
- = link_to 'Test settings', test_project_service_path(@project), class: 'btn btn-small'
diff --git a/app/views/services/edit.html.haml b/app/views/services/edit.html.haml
index 0c63a7ed58c..d4bc9e41c27 100644
--- a/app/views/services/edit.html.haml
+++ b/app/views/services/edit.html.haml
@@ -1,3 +1,3 @@
= render "projects/settings_nav"
-= render 'gitlab_ci'
+= render 'form'
diff --git a/app/views/services/index.html.haml b/app/views/services/index.html.haml
index eb2f8d0ca1c..bd52948a6fd 100644
--- a/app/views/services/index.html.haml
+++ b/app/views/services/index.html.haml
@@ -3,30 +3,16 @@
%h3.page_title Services
%br
-%ul.ui-box.well-list
- %li
- %h4.cgreen
- = link_to edit_project_service_path(@project, :gitlab_ci) do
- GitLab CI
- %small Continuous integration server from GitLab
- .pull-right
- - if @gitlab_ci_service.try(:active)
- %small.cgreen
- %i.icon-ok
- Enabled
+%ul.bordered-list
+ - @services.each do |service|
+ %li
+ %h4
+ - if service.activated?
+ %span.cgreen
+ %i.icon-circle
- else
- %small.cgray
- %i.icon-off
- Disabled
- %li.disabled
- %h4
- Jenkins CI
- %small An extendable open source continuous integration server
- .pull-right
- %small Not implemented yet
- %li.disabled
- %h4
- Campfire
- %small Web-based group chat tool
- .pull-right
- %small Not implemented yet
+ %span.cgray
+ %i.icon-circle-blank
+ = link_to edit_project_service_path(@project, service.to_param) do
+ = service.title
+ %p= service.description
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index bd9ca729352..62e0fa25898 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -1,4 +1,13 @@
-.input-prepend.project_clone_holder
+.input-prepend.input-append.project_clone_holder
%button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH
- %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
- = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
+ %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= gitlab_config.protocol.upcase
+ = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span7", readonly: true
+ %span.add-on
+ - if @project.public
+ .cblue
+ %i.icon-share
+ public
+ - else
+ .cgreen
+ %i.icon-lock
+ private
diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml
index 85391a34316..a2800b11d8d 100644
--- a/app/views/shared/_merge_requests.html.haml
+++ b/app/views/shared/_merge_requests.html.haml
@@ -4,7 +4,7 @@
- project = group[0]
%h5.title
= link_to_project project
- %ul.well-list
+ %ul.well-list.mr-list
- group[1].each do |merge_request|
= render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request})
%hr
diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml
new file mode 100644
index 00000000000..c97f8ba0f0e
--- /dev/null
+++ b/app/views/shared/_promo.html.haml
@@ -0,0 +1,4 @@
+.gitlab-promo
+ = link_to "Homepage", "http://gitlab.org"
+ = link_to "Blog", "http://blog.gitlab.org"
+ = link_to "@gitlabhq", "https://twitter.com/gitlabhq"
diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml
index 8b44cf1944e..dc8c656e12e 100644
--- a/app/views/shared/_ref_switcher.html.haml
+++ b/app/views/shared/_ref_switcher.html.haml
@@ -3,3 +3,5 @@
= hidden_field_tag :destination, destination
- if defined?(path)
= hidden_field_tag :path, path
+ - @options && @options.each do |key, value|
+ = hidden_field_tag key, value, id: nil
diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml
index d9514890b20..95e9e0357bc 100644
--- a/app/views/snippets/_form.html.haml
+++ b/app/views/snippets/_form.html.haml
@@ -33,7 +33,7 @@
= f.submit 'Save', class: "btn-save btn"
= link_to "Cancel", snippets_path(@project), class: " btn"
- unless @snippet.new_record?
- .pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
+ .pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
:javascript
diff --git a/app/views/team_members/_assigned_team.html.haml b/app/views/team_members/_assigned_team.html.haml
index 1d512c44b26..51a31a6456d 100644
--- a/app/views/team_members/_assigned_team.html.haml
+++ b/app/views/team_members/_assigned_team.html.haml
@@ -1,7 +1,7 @@
%li{id: dom_id(team), class: "user_team_row team_#{team.id}"}
.pull-right
- if can?(current_user, :admin_team_member, @project)
- = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove btn-tiny" do
+ = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you sure?", class: "btn btn-remove btn-tiny" do
%i.icon-minus.icon-white
%strong= link_to team.name, team_path(team), title: team.name, class: "dark"
diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml
index 2ec8c1a8451..4b49b308edc 100644
--- a/app/views/team_members/_team.html.haml
+++ b/app/views/team_members/_team.html.haml
@@ -1,8 +1,9 @@
- team.each do |access, members|
- .ui-box
+ - role = Project.access_options.key(access).pluralize
+ .ui-box{class: role.downcase}
%h5.title
- = Project.access_options.key(access).pluralize
- %small= members.size
+ = role
+ %span.light (#{members.size})
%ul.well-list
- members.sort_by(&:user_name).each do |team_member|
= render 'team_members/team_member', member: team_member
diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml
index 2b0709beb92..5fd8d2465d1 100644
--- a/app/views/team_members/_team_member.html.haml
+++ b/app/views/team_members/_team_member.html.haml
@@ -16,11 +16,11 @@
= f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit"
.pull-right
- if current_user == user
- %span.label This is you!
+ %span.label.label-success This is you!
- if @project.namespace_owner == user
- %span.label Owner
+ %span.label.label-info Owner
- elsif user.blocked?
- %span.label Blocked
+ %span.label.label-error Blocked
- elsif allow_admin
= link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.icon-minus.icon-white
diff --git a/app/views/team_members/create.js.haml b/app/views/team_members/create.js.haml
deleted file mode 100644
index b7dff35a269..00000000000
--- a/app/views/team_members/create.js.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- if @user_project_relation.valid?
- :plain
- $("#new_team_member").hide("slide", { direction: "right" }, 150, function(){
- $("#team-table").show("slide", { direction: "left" }, 150, function() {
- $("#new_team_member").remove();
- $("#team-table").replaceWith("#{escape_javascript(render('projects/team'))}");
- $(".add_new").show();
- });
- });
-- else
- :plain
- $("#new_team_member").replaceWith("#{escape_javascript(render('form'))}");
- $('select#team_member_user_id').chosen();
diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml
index 50d44bcd8d8..3132fd5ca8a 100644
--- a/app/views/team_members/index.html.haml
+++ b/app/views/team_members/index.html.haml
@@ -22,22 +22,22 @@
.span3
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if !params[:type])}
- = link_to project_team_members_path(type: nil) do
+ = link_to project_team_index_path(type: nil) do
All
%li{class: ("active" if params[:type] == 'masters')}
- = link_to project_team_members_path(type: 'masters') do
+ = link_to project_team_index_path(type: 'masters') do
Masters
%span.pull-right= @project.users_projects.masters.count
%li{class: ("active" if params[:type] == 'developers')}
- = link_to project_team_members_path(type: 'developers') do
+ = link_to project_team_index_path(type: 'developers') do
Developers
%span.pull-right= @project.users_projects.developers.count
%li{class: ("active" if params[:type] == 'reporters')}
- = link_to project_team_members_path(type: 'reporters') do
+ = link_to project_team_index_path(type: 'reporters') do
Reporters
%span.pull-right= @project.users_projects.reporters.count
%li{class: ("active" if params[:type] == 'guests')}
- = link_to project_team_members_path(type: 'guests') do
+ = link_to project_team_index_path(type: 'guests') do
Guests
%span.pull-right= @project.users_projects.guests.count
diff --git a/app/views/teams/issues.html.haml b/app/views/teams/issues.html.haml
index 5b17c5d4f0b..94818ccd7f4 100644
--- a/app/views/teams/issues.html.haml
+++ b/app/views/teams/issues.html.haml
@@ -14,7 +14,7 @@
- @project = group[0]
%h5.title
= link_to_project @project
- %ul.well-list.issues_table
+ %ul.well-list.issues-list
- group[1].each do |issue|
= render issue
%hr
diff --git a/app/views/teams/members/_member.html.haml b/app/views/teams/members/_member.html.haml
new file mode 100644
index 00000000000..17096d2f1cd
--- /dev/null
+++ b/app/views/teams/members/_member.html.haml
@@ -0,0 +1,31 @@
+- user = member.user
+- allow_admin = can? current_user, :manage_user_team, @team
+%li{id: dom_id(member), class: "team_member_row user_#{user.id}"}
+ .row
+ .span3
+ = link_to user_path(user.username), title: user.name, class: "dark" do
+ = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
+ = link_to user_path(user.username), title: user.name, class: "dark" do
+ %strong= truncate(user.name, lenght: 40)
+ %br
+ %small.cgray= user.username
+
+ .span5.pull-right
+ - if allow_admin
+ .pull-left
+ = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f|
+ = label_tag :group_admin do
+ = f.check_box :group_admin, class: 'trigger-submit'
+ %span Admin access
+ &nbsp;
+ = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "span2 trigger-submit"
+ .pull-right
+ - if current_user == user
+ %span.label.label-success This is you!
+ - if @team.owner == user
+ %span.label.label-info Owner
+ - elsif user.blocked?
+ %span.label.label-error Blocked
+ - elsif allow_admin
+ = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do
+ %i.icon-minus.icon-white
diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml
deleted file mode 100644
index 1a323043d09..00000000000
--- a/app/views/teams/members/_show.html.haml
+++ /dev/null
@@ -1,30 +0,0 @@
-- user = member.user
-- allow_admin = can? current_user, :manage_user_team, @team
-%li{id: dom_id(member), class: "team_member_row user_#{user.id}"}
- .row
- .span5
- = link_to user_path(user.username), title: user.name, class: "dark" do
- = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
- = link_to user_path(user.username), title: user.name, class: "dark" do
- %strong= truncate(user.name, lenght: 40)
- %br
- %small.cgray= user.username
-
- .span4
- - if allow_admin
- = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f|
- = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit"
- %br
- = label_tag do
- = f.check_box :group_admin, class: 'trigger-submit'
- %span Admin access
- .pull-right
- - if current_user == user
- %span.btn.disabled This is you!
- - if @team.owner == user
- %span.btn.disabled Owner
- - elsif user.blocked?
- %span.btn.disabled.blocked Blocked
- - elsif allow_admin
- = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do
- %i.icon-minus.icon-white
diff --git a/app/views/teams/members/_team.html.haml b/app/views/teams/members/_team.html.haml
index d8afc1fa371..52bb597cd80 100644
--- a/app/views/teams/members/_team.html.haml
+++ b/app/views/teams/members/_team.html.haml
@@ -1,16 +1,10 @@
-- grouped_user_team_members(@team).each do |access, members|
+- grouped_user_team_members(team).each do |access, members|
+ - access_key = Project.access_options.key(access)
+ - next if params[:type].present? && params[:type] != access_key.tableize
.ui-box
%h5.title
- = Project.access_options.key(access).pluralize
+ = access_key.pluralize
%small= members.size
- %ul.well-list
- - members.sort_by(&:user_name).each do |up|
- = render(partial: 'teams/members/show', locals: {member: up})
-
-
-:javascript
- $(function(){
- $('.repo-access-select, .project-access-select').live("change", function() {
- $(this.form).submit();
- });
- })
+ %ul.well-list.team-members
+ - members.sort_by(&:user_name).each do |member|
+ = render 'teams/members/member', member: member
diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml
index 87438266cfb..02700e9fb71 100644
--- a/app/views/teams/members/index.html.haml
+++ b/app/views/teams/members/index.html.haml
@@ -12,6 +12,26 @@
%hr
-.clearfix
-%div.team-table
- = render partial: "teams/members/team", locals: {project: @team}
+.row
+ .span3
+ %ul.nav.nav-pills.nav-stacked
+ %li{class: ("active" if !params[:type])}
+ = link_to team_members_path(@team, type: nil) do
+ All
+ %li{class: ("active" if params[:type] == 'masters')}
+ = link_to team_members_path(@team, type: 'masters') do
+ Masters
+ %li{class: ("active" if params[:type] == 'developers')}
+ = link_to team_members_path(@team, type: 'developers') do
+ Developers
+ %li{class: ("active" if params[:type] == 'reporters')}
+ = link_to team_members_path(@team, type: 'reporters') do
+ Reporters
+ %li{class: ("active" if params[:type] == 'guests')}
+ = link_to team_members_path(@team, type: 'guests') do
+ Guests
+
+ .span9
+ .clearfix
+ %div.team-table
+ = render "teams/members/team", team: @team
diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml
index 9b9b3cef59b..99530ebb7f0 100644
--- a/app/views/teams/members/new.html.haml
+++ b/app/views/teams/members/new.html.haml
@@ -1,29 +1,25 @@
%h3.page_title
Team: #{@team.name}
-%fieldset
- %legend Members (#{@team.members.count})
- = form_tag team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do
- %table#members_list
- %thead
- %tr
- %th User name
- %th Default project access
- %th Team access
- %th
- - @team.members.each do |member|
- %tr.member
- %td
- = member.name
- %small= "(#{member.username})"
- %td= @team.human_default_projects_access(member)
- %td= @team.admin?(member) ? "Admin" : "Member"
- %td
- %tr
- %td
- = users_select_tag(:user_ids, multiple: true)
- %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" }
- %td
- %span= check_box_tag :group_admin
- %span Admin?
- %td= submit_tag 'Add User', class: "btn btn-create", id: :add_members_to_team
+%hr
+
+= form_tag team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do
+ %h6 1. Choose people you want in the team
+ .clearfix
+ = label_tag :user_ids, "People"
+ .input
+ = users_select_tag(:user_ids, multiple: true)
+
+ %h6 2. Set access level for them
+ .clearfix
+ = label_tag :project_access, "Project Access"
+ .input= select_tag :default_project_access, options_for_select(Project.access_options), class: "project-access-select chosen"
+
+ .clearfix
+ = label_tag :group_admin do
+ %span Team Admin?
+ .input= check_box_tag :group_admin
+
+ .actions
+ = submit_tag 'Add users', class: "btn btn-create", id: :add_members_to_team
+ = link_to "Cancel", team_members_path(@team), class: "btn btn-cancel"
diff --git a/app/views/teams/show.atom.builder b/app/views/teams/show.atom.builder
index bb0f666e860..fffb78d53e8 100644
--- a/app/views/teams/show.atom.builder
+++ b/app/views/teams/show.atom.builder
@@ -8,10 +8,9 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
@events.each do |event|
if event.proper?
- event = EventDecorator.decorate(event)
xml.entry do
- event_link = event.feed_url
- event_title = event.feed_title
+ event_link = event_feed_url(event)
+ event_title = event_feed_title(event)
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link :href => event_link
diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml
index 2eb0283e0ab..2ad7f743010 100644
--- a/app/views/teams/show.html.haml
+++ b/app/views/teams/show.html.haml
@@ -1,4 +1,4 @@
-.projects
+.dashboard
.activities.span8
= link_to dashboard_path, class: 'btn btn-tiny' do
&larr; To dashboard
@@ -12,7 +12,7 @@
.loading.hide
.side.span4
- if @team.description.present?
- .description.well.light
+ .description.well.well-small.light
= @team.description
= render "projects", projects: @projects
.prepend-top-20
@@ -22,10 +22,4 @@
News Feed
%hr
- .gitlab-promo
- = link_to "Homepage", "http://gitlabhq.com"
- = link_to "Blog", "http://blog.gitlabhq.com"
- = link_to "@gitlabhq", "https://twitter.com/gitlabhq"
-
-:javascript
- $(function(){ Pager.init(20, true); });
+ = render 'shared/promo'
diff --git a/app/views/tree/_blob.html.haml b/app/views/tree/_blob.html.haml
deleted file mode 100644
index ebf1ee2c678..00000000000
--- a/app/views/tree/_blob.html.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-.file_holder
- .file_title
- %i.icon-file
- %span.file_name
- = blob.name
- %small= number_to_human_size blob.size
- %span.options= render "tree/blob_actions"
- - if blob.text?
- = render "tree/blob/text", blob: blob
- - elsif blob.image?
- = render "tree/blob/image", blob: blob
- - else
- = render "tree/blob/download", blob: blob
diff --git a/app/views/tree/_blob_item.html.haml b/app/views/tree/_blob_item.html.haml
new file mode 100644
index 00000000000..ec15b608f85
--- /dev/null
+++ b/app/views/tree/_blob_item.html.haml
@@ -0,0 +1,9 @@
+%tr{ class: "tree-item #{tree_hex_class(blob_item)}" }
+ %td.tree-item-file-name
+ = tree_icon(type)
+ %strong= link_to truncate(blob_item.name, length: 40), 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
+ %td.tree_commit{ colspan: 2 }
diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml
index 24a57ae7a29..cc45faa1459 100644
--- a/app/views/tree/_tree.html.haml
+++ b/app/views/tree/_tree.html.haml
@@ -3,7 +3,7 @@
%i.icon-angle-right
= link_to project_tree_path(@project, @ref) do
= @project.path
- - tree.breadcrumbs(6) do |title, path|
+ - tree_breadcrumbs(tree, 6) do |title, path|
\/
%li
- if path
@@ -12,36 +12,40 @@
= link_to title, '#'
%div#tree-content-holder.tree-content-holder
- - if tree.is_blob?
- = render "tree/blob", blob: tree
- - else
- %table#tree-slider{class: "table_#{@hex_path} tree-table" }
- %thead
- %tr
- %th Name
- %th Last Update
- %th Last Commit
- %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right"
+ %table#tree-slider{class: "table_#{@hex_path} tree-table" }
+ %thead
+ %tr
+ %th Name
+ %th Last Update
+ %th
+ Last Commit
+ &nbsp;
+ %i.icon-angle-right
+ &nbsp;
+ %small.light
+ = link_to @commit.short_id, project_commit_path(@project, @commit)
+ &ndash;
+ = truncate(@commit.title, length: 50)
+ %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right"
- - if tree.up_dir?
- %tr.tree-item
- %td.tree-item-file-name
- = image_tag "file_empty.png", size: '16x16'
- = link_to "..", project_tree_path(@project, tree.up_dir_path)
- %td
- %td
- %td
+ - if tree.up_dir?
+ %tr.tree-item
+ %td.tree-item-file-name
+ = image_tag "file_empty.png", size: '16x16'
+ = link_to "..", project_tree_path(@project, up_dir_path(tree))
+ %td
+ %td
+ %td
- = render_tree(tree.contents)
+ = render_tree(tree)
- - if tree.readme
- = render "tree/readme", readme: tree.readme
+ - if tree.readme
+ = render "tree/readme", readme: tree.readme
%div.tree_progress
-- unless tree.is_blob?
- :javascript
- // Load last commit log for each file in tree
- $(window).load(function(){
- ajaxGet('#{@logs_path}');
- });
+:javascript
+ // Load last commit log for each file in tree
+ $('#tree-slider').waitForImages(function() {
+ ajaxGet('#{@logs_path}');
+ });
diff --git a/app/views/tree/_tree_commit_column.html.haml b/app/views/tree/_tree_commit_column.html.haml
index 9d02132b0f4..7ae2582c130 100644
--- a/app/views/tree/_tree_commit_column.html.haml
+++ b/app/views/tree/_tree_commit_column.html.haml
@@ -1,2 +1,2 @@
-%span.tree_author= commit.author_link avatar: true
+%span.tree_author= commit_author_link(commit, avatar: true)
= link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link"
diff --git a/app/views/tree/show.js.haml b/app/views/tree/show.js.haml
deleted file mode 100644
index fadd5e2251f..00000000000
--- a/app/views/tree/show.js.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-:plain
- // Load Files list
- $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {tree: @tree}))}");
- $("#tree-content-holder").show("slide", { direction: "right" }, 150);
- $('.project-refs-form #path').val("#{@path}");
-
- // Load last commit log for each file in tree
- $('#tree-slider').waitForImages(function() {
- ajaxGet('#{@logs_path}');
- });
diff --git a/app/views/votes/_votes_inline.html.haml b/app/views/votes/_votes_inline.html.haml
index 91bd200df44..ee805474830 100644
--- a/app/views/votes/_votes_inline.html.haml
+++ b/app/views/votes/_votes_inline.html.haml
@@ -1,6 +1,9 @@
.votes.votes-inline
- .upvotes= votable.upvotes
- .progress
- .bar.bar-success{style: "width: #{votable.upvotes_in_percent}%;"}
- .bar.bar-danger{style: "width: #{votable.downvotes_in_percent}%;"}
- .downvotes= votable.downvotes
+ - unless votable.upvotes.zero?
+ .upvotes
+ + #{votable.upvotes}
+ - unless votable.downvotes.zero?
+ \/
+ - unless votable.downvotes.zero?
+ .downvotes
+ \- #{votable.downvotes}
diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml
index 0cd29486d93..88aecee0815 100644
--- a/app/views/walls/show.html.haml
+++ b/app/views/walls/show.html.haml
@@ -1,5 +1,5 @@
%div.wall-page
- %ul.well-list.notes
+ %ul.notes
- if can? current_user, :write_note, @project
.note-form-holder
@@ -12,11 +12,6 @@
= f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
.note-form-option
- = label_tag :notify do
- = check_box_tag :notify, 1, false
- %span.light Notify team via email
-
- .note-form-option
%a.choose-btn.btn.btn-small.js-choose-note-attachment-button
%i.icon-paper-clip
%span Choose File ...
@@ -26,8 +21,3 @@
.hint.pull-right CTRL + Enter to send message
.clearfix
-
-:javascript
- $(function(){
- Wall.init(#{@project.id});
- });
diff --git a/app/views/wikis/_nav.html.haml b/app/views/wikis/_nav.html.haml
index 0dffdd8fc14..09a1986e105 100644
--- a/app/views/wikis/_nav.html.haml
+++ b/app/views/wikis/_nav.html.haml
@@ -11,8 +11,8 @@
Git Access
- if can?(current_user, :write_wiki, @project)
- %li.pull-right
- = link_to '#', class: "add-new-wiki" do
+ .pull-right
+ = link_to '#', class: "add-new-wiki btn btn-small btn-primary" do
%i.icon-plus
New Page
diff --git a/app/views/wikis/_new.html.haml b/app/views/wikis/_new.html.haml
index 50b40bff41c..ca8e7c1b4b4 100644
--- a/app/views/wikis/_new.html.haml
+++ b/app/views/wikis/_new.html.haml
@@ -1,25 +1,12 @@
%div#modal-new-wiki.modal.hide
.modal-header
%a.close{href: "#"} ×
- %h3 New Wiki Page
+ %h3.page_title New Wiki Page
.modal-body
= label_tag :new_wiki_path do
%span Page slug
- = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'input-xlarge'
+ = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'input-xlarge', required: true, :'data-wikis-path' => project_wikis_path(@project)
+ %p.hint
+ Please dont use spaces and slashes
.modal-footer
= link_to 'Build', '#', class: 'build-new-wiki btn btn-create'
-
-:javascript
- $(function(){
- var modal = $('#modal-new-wiki').modal({modal: true, show:false});
- $('.add-new-wiki').bind("click", function(){
- modal.show();
- });
- $('.build-new-wiki').bind("click", function(){
- location.href = "#{project_wikis_path(@project)}/" + $('#new_wiki_path').val();
- });
- $('.modal-header .close').bind("click", function(){
- modal.hide();
- })
- })
-
diff --git a/app/views/wikis/git_access.html.haml b/app/views/wikis/git_access.html.haml
index 58c8aa06aca..462d483fd85 100644
--- a/app/views/wikis/git_access.html.haml
+++ b/app/views/wikis/git_access.html.haml
@@ -24,8 +24,8 @@
%legend Clone Your Wiki:
%pre.dark
:preserve
- git clone #{@gollum_wiki.path_with_namespace}.git
- cd #{@gollum_wiki.path_with_namespace}
+ git clone #{@gollum_wiki.ssh_url_to_repo}
+ cd #{@gollum_wiki.path}
%legend Start Gollum And Edit Locally:
%pre.dark
diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml
index 599e9cf6793..f4946ed000d 100644
--- a/app/views/wikis/history.html.haml
+++ b/app/views/wikis/history.html.haml
@@ -14,12 +14,13 @@
%th Format
%tbody
- @wiki.versions.each do |version|
- - commit = CommitDecorator.new(version)
+ - commit = version
%tr
%td
= link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
= commit.short_id
- %td= commit.author_link avatar: true, size: 24
+ %td
+ = commit_author_link(commit, avatar: true, size: 24)
%td
= commit.title
%td
diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml
index eb65599d087..95d5eef16f5 100644
--- a/app/views/wikis/pages.html.haml
+++ b/app/views/wikis/pages.html.haml
@@ -21,5 +21,5 @@
= wiki_page.created_at.to_s(:short) do
(#{time_ago_in_words(wiki_page.created_at)}
ago)
- - commit = CommitDecorator.decorate(wiki_page.version)
- %td= commit.author_link avatar: true, size: 24
+ %td
+ = commit_author_link(wiki_page.version, avatar: true, size: 24)
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index b660a15ee32..b237bc524ed 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -13,5 +13,4 @@
= preserve do
= render_wiki_content(@wiki)
-- commit = CommitDecorator.new(@wiki.version)
-%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago
+%p.time Last edited by #{commit_author_link(@wiki.version, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 72cef0fd295..6416aa608ec 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -1,5 +1,6 @@
class PostReceive
include Sidekiq::Worker
+ include Gitlab::Identifier
sidekiq_options queue: :post_receive
@@ -8,7 +9,7 @@ class PostReceive
if repo_path.start_with?(Gitlab.config.gitlab_shell.repos_path.to_s)
repo_path.gsub!(Gitlab.config.gitlab_shell.repos_path.to_s, "")
else
- Gitlab::GitLogger.error("POST-RECEIVE: Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"")
+ log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"")
end
repo_path.gsub!(/.git$/, "")
@@ -17,31 +18,21 @@ class PostReceive
project = Project.find_with_namespace(repo_path)
if project.nil?
- Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing project with full path \"#{repo_path} \"")
+ log("Triggered hook for non-existing project with full path \"#{repo_path} \"")
return false
end
- user = if identifier.blank?
- # Local push from gitlab
- email = project.repository.commit(newrev).author.email rescue nil
- User.find_by_email(email) if email
-
- elsif identifier =~ /\Auser-\d+\Z/
- # git push over http
- user_id = identifier.gsub("user-", "")
- User.find_by_id(user_id)
-
- elsif identifier =~ /\Akey-\d+\Z/
- # git push over ssh
- key_id = identifier.gsub("key-", "")
- Key.find_by_id(key_id).try(:user)
- end
+ user = identify(identifier, project, newrev)
unless user
- Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing user \"#{identifier} \"")
+ log("Triggered hook for non-existing user \"#{identifier} \"")
return false
end
GitPushService.new.execute(project, user, oldrev, newrev, ref)
end
+
+ def log(message)
+ Gitlab::GitLogger.error("POST-RECEIVE: #{message}")
+ end
end