diff options
Diffstat (limited to 'app/views/shared')
39 files changed, 653 insertions, 211 deletions
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index 687a59c270f..faf7e49ed29 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -1,7 +1,7 @@ - project = project || @project -.git-clone-holder - .btn-group.clone-options +.git-clone-holder.input-group + .input-group-btn %a#clone-dropdown.clone-dropdown-btn.btn{href: '#', 'data-toggle' => 'dropdown'} %span = default_clone_protocol.upcase diff --git a/app/views/shared/_commit_message_container.html.haml b/app/views/shared/_commit_message_container.html.haml index 7c57924277e..7afbaeddee8 100644 --- a/app/views/shared/_commit_message_container.html.haml +++ b/app/views/shared/_commit_message_container.html.haml @@ -7,7 +7,7 @@ .max-width-marker = text_area_tag 'commit_message', (params[:commit_message] || local_assigns[:text]), - class: 'form-control js-commit-message js-quick-submit', placeholder: local_assigns[:placeholder], + class: 'form-control js-commit-message', placeholder: local_assigns[:placeholder], required: true, rows: (local_assigns[:rows] || 3), id: "commit_message-#{nonce}" - if local_assigns[:hint] diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml index 8495774accc..c38d9313dba 100644 --- a/app/views/shared/_event_filter.html.haml +++ b/app/views/shared/_event_filter.html.haml @@ -1,4 +1,4 @@ -.btn-group.btn-group-next.event-filter +%ul.nav-links.event-filter = event_filter_link EventFilter.push, 'Push events' = event_filter_link EventFilter.merged, 'Merge events' = event_filter_link EventFilter.comments, 'Comments' diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 2bc98983d67..57856031d6e 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,13 +1,12 @@ -.file-content.code.js-syntax-highlight{ class: user_color_scheme } +.file-content.code.js-syntax-highlight .line-numbers - if blob.data.present? - - blob.data.lines.each_index do |index| + - blob.data.each_line.each_with_index do |_, index| - offset = defined?(first_line_number) ? first_line_number : 1 - i = index + offset -# We're not using `link_to` because it is too slow once we get to thousands of lines. - %a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i} + %a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i} %i.fa.fa-link = i .blob-content{data: {blob_id: blob.id}} - :preserve - #{highlight(blob.name, blob.data)} + = highlight(blob.name, blob.data) diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml index 285af56ad73..627814bcfae 100644 --- a/app/views/shared/_import_form.html.haml +++ b/app/views/shared/_import_form.html.haml @@ -11,6 +11,6 @@ %li If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>. %li - The import will time out after 4 minutes. For big repositories, use a clone/push combination. + The import will time out after 15 minutes. For repositories that take longer, use a clone/push combination. %li To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}. diff --git a/app/views/shared/_issues.html.haml b/app/views/shared/_issues.html.haml index 4b4c9e9eabe..8ff9d4c1c7f 100644 --- a/app/views/shared/_issues.html.haml +++ b/app/views/shared/_issues.html.haml @@ -8,7 +8,7 @@ .pull-right = link_to 'New issue', new_namespace_project_issue_path(project.namespace, project) - %ul.well-list.issues-list + %ul.content-list.issues-list - group[1].each do |issue| = render 'projects/issues/issue', issue: issue = paginate @issues, theme: "gitlab" diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml new file mode 100644 index 00000000000..8134b15d245 --- /dev/null +++ b/app/views/shared/_label_row.html.haml @@ -0,0 +1,4 @@ +%span.label-row + = link_to_label(label) + %span.prepend-left-10 + = markdown(label.description, pipeline: :single_line) diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg index da49c48acd3..b07f1c5603e 100644 --- a/app/views/shared/_logo.svg +++ b/app/views/shared/_logo.svg @@ -1,21 +1,9 @@ -<svg width="36px" height="36px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="tanuki-logo"> - <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> - <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)"> - <g id="Page-1" sketch:type="MSShapeGroup"> - <g id="Fill-1-+-Group-24"> - <g id="Group-24"> - <g id="Group"> - <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path> - <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path> - <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path> - <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path> - <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path> - <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path> - <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path> - </g> - </g> - </g> - </g> - </g> - </g> +<svg width="36" height="36" id="tanuki-logo"> + <path id="tanuki-right-ear" class="tanuki-shape" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/> + <path id="tanuki-left-ear" class="tanuki-shape" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/> + <path id="tanuki-nose" class="tanuki-shape" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/> + <path id="tanuki-right-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 11.38,14 2,14 6,25Z"/> + <path id="tanuki-left-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 24.62,14 34,14 30,25Z"/> + <path id="tanuki-right-cheek" class="tanuki-shape" fill="#fca326" d="M2 14L.1 20.16c-.18.565 0 1.2.5 1.56l17.42 12.66z"/> + <path id="tanuki-left-cheek" class="tanuki-shape" fill="#fca326" d="M34 14l1.9 6.16c.18.565 0 1.2-.5 1.56L18 34.38z"/> </svg> diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml index be17a511b26..e74fc36c797 100644 --- a/app/views/shared/_merge_requests.html.haml +++ b/app/views/shared/_merge_requests.html.haml @@ -8,7 +8,7 @@ .pull-right = link_to 'New merge request', new_namespace_project_merge_request_path(project.namespace, project) - %ul.well-list.mr-list + %ul.content-list.mr-list - group[1].each do |merge_request| = render 'projects/merge_requests/merge_request', merge_request: merge_request = paginate @merge_requests, theme: "gitlab" diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index cbdecda4fff..cf16c203f9c 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,11 +1,10 @@ -.milestones-filters - %ul.center-top-menu - %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} - = link_to milestones_filter_path(state: 'opened') do - Open - %li{class: ("active" if params[:state] == 'closed')} - = link_to milestones_filter_path(state: 'closed') do - Closed - %li{class: ("active" if params[:state] == 'all')} - = link_to milestones_filter_path(state: 'all') do - All +%ul.nav-links + %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} + = link_to milestones_filter_path(state: 'opened') do + Open + %li{class: ("active" if params[:state] == 'closed')} + = link_to milestones_filter_path(state: 'closed') do + Closed + %li{class: ("active" if params[:state] == 'all')} + = link_to milestones_filter_path(state: 'all') do + All diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index c4431d66927..1c58345278a 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,6 +1,6 @@ - if @projects.any? - .prepend-left-10.new-project-item-select-holder - = project_select_tag :project_path, class: "new-project-item-select", data: { include_groups: local_assigns[:include_groups] } + .prepend-left-10.project-item-select-holder + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' } %a.btn.btn-new.new-project-item-select-button = icon('plus') = local_assigns[:label] @@ -8,12 +8,12 @@ :javascript $('.new-project-item-select-button').on('click', function() { - $('.new-project-item-select').select2('open'); + $('.project-item-select').select2('open'); }); var relativePath = '#{local_assigns[:path]}'; - $('.new-project-item-select').on('click', function() { + $('.project-item-select').on('click', function() { window.location = $(this).val() + '/' + relativePath; }); diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml index 089179e677a..bb5fff2d3bb 100644 --- a/app/views/shared/_no_ssh.html.haml +++ b/app/views/shared/_no_ssh.html.haml @@ -1,6 +1,6 @@ - if cookies[:hide_no_ssh_message].blank? && !current_user.hide_no_ssh_key && current_user.require_ssh_key? .no-ssh-key-message.alert.alert-warning.hidden-xs - You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path, class: 'alert-link'} to your profile + You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', profile_keys_path, class: 'alert-link'} to your profile .pull-right = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'alert-link' diff --git a/app/views/shared/_project_limit.html.haml b/app/views/shared/_project_limit.html.haml index 960ff00b49d..f4eb8e491b9 100644 --- a/app/views/shared/_project_limit.html.haml +++ b/app/views/shared/_project_limit.html.haml @@ -1,4 +1,4 @@ -- if cookies[:hide_project_limit_message].blank? && !current_user.hide_project_limit && !current_user.can_create_project? +- if cookies[:hide_project_limit_message].blank? && !current_user.hide_project_limit && !current_user.can_create_project? && current_user.projects_limit > 0 .project-limit-message.alert.alert-warning.hidden-xs You won't be able to create new projects because you have reached your project limit. diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml index 3596aabe309..09edf4000d5 100644 --- a/app/views/shared/_promo.html.haml +++ b/app/views/shared/_promo.html.haml @@ -1,5 +1,5 @@ .gitlab-promo = link_to 'Homepage', promo_url - = link_to "Blog", promo_url + '/blog/' - = link_to "@gitlab", "https://twitter.com/gitlab" - = link_to "Requests", "http://feedback.gitlab.com/" + = link_to 'Blog', promo_url + '/blog/' + = link_to '@gitlab', 'https://twitter.com/gitlab' + = link_to 'Requests', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#feature-proposals' diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml index 28d6f421fea..5a60ff5a5da 100644 --- a/app/views/shared/_service_settings.html.haml +++ b/app/views/shared/_service_settings.html.haml @@ -50,7 +50,7 @@ = form.label :issues_events, class: 'list-label' do %strong Issues events %p.light - This url will be triggered when an issue is created + This url will be triggered when an issue is created/updated/merged - if @service.supported_events.include?("merge_request") %div = form.check_box :merge_requests_events, class: 'pull-left' @@ -58,7 +58,7 @@ = form.label :merge_requests_events, class: 'list-label' do %strong Merge Request events %p.light - This url will be triggered when a merge request is created + This url will be triggered when a merge request is created/updated/merged - if @service.supported_events.include?("build") %div = form.check_box :build_events, class: 'pull-left' diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml index af3d35de325..e3a6a5a68b6 100644 --- a/app/views/shared/_sort_dropdown.html.haml +++ b/app/views/shared/_sort_dropdown.html.haml @@ -1,6 +1,6 @@ .dropdown.inline.prepend-left-10 %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else @@ -20,3 +20,7 @@ = sort_title_milestone_soon = link_to page_filter_path(sort: sort_value_milestone_later) do = sort_title_milestone_later + = link_to page_filter_path(sort: sort_value_upvotes) do + = sort_title_upvotes + = link_to page_filter_path(sort: sort_value_downvotes) do + = sort_title_downvotes diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml index a54c5fa8c33..fb9a8db0889 100644 --- a/app/views/shared/groups/_group.html.haml +++ b/app/views/shared/groups/_group.html.haml @@ -1,5 +1,8 @@ - group_member = local_assigns[:group_member] -%li +- css_class = '' unless local_assigns[:css_class] +- css_class += " no-description" if group.description.blank? + +%li.group-row{ class: css_class } - if group_member .controls.hidden-xs - if can?(current_user, :admin_group, group) @@ -9,14 +12,23 @@ = link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Leave this group' do %i.fa.fa-sign-out - = image_tag group_icon(group), class: "avatar s46 hidden-xs" - = link_to group, class: 'group-name' do - %strong= group.name + .stats + %span + = icon('home') + = number_with_delimiter(group.projects.count) + + %span + = icon('users') + = number_with_delimiter(group.users.count) + + = image_tag group_icon(group), class: "avatar s40 hidden-xs" + = link_to group, class: 'group-name title' do + = group.name - if group_member as %span #{group_member.human_access} - %div.light - #{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")} - + - if group.description.present? + .description + = markdown(group.description, pipeline: :description) diff --git a/app/views/shared/groups/_list.html.haml b/app/views/shared/groups/_list.html.haml new file mode 100644 index 00000000000..1aa7ed1f2eb --- /dev/null +++ b/app/views/shared/groups/_list.html.haml @@ -0,0 +1,6 @@ +- if groups.any? + %ul.content-list + - groups.each_with_index do |group, i| + = render "shared/groups/group", group: group +- else + %h3 No groups found diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index be06738eac9..dfdc84ba4cc 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -1,28 +1,5 @@ .issues-filters - .issues-state-filters - %ul.center-top-menu - %li{class: ("active" if params[:state] == 'opened')} - = link_to page_filter_path(state: 'opened') do - #{state_filters_text_for(:opened, @project)} - - - if defined?(type) && type == :merge_requests - %li{class: ("active" if params[:state] == 'merged')} - = link_to page_filter_path(state: 'merged') do - #{state_filters_text_for(:merged, @project)} - - %li{class: ("active" if params[:state] == 'closed')} - = link_to page_filter_path(state: 'closed') do - #{state_filters_text_for(:closed, @project)} - - else - %li{class: ("active" if params[:state] == 'closed')} - = link_to page_filter_path(state: 'closed') do - #{state_filters_text_for(:closed, @project)} - - %li{class: ("active" if params[:state] == 'all')} - = link_to page_filter_path(state: 'all') do - #{state_filters_text_for(:all, @project)} - - .issues-details-filters.gray-content-block + .issues-details-filters.gray-content-block.second-block = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do - if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project) .check-all-holder @@ -30,22 +7,77 @@ class: "check_all_issues left" .issues-other-filters .filter-item.inline - = users_select_tag(:author_id, selected: params[:author_id], - placeholder: 'Author', class: 'trigger-submit', any_user: "Any Author", first_user: true, current_user: true) + - if params[:author_id] + = hidden_field_tag(:author_id, params[:author_id]) + = dropdown_tag(user_dropdown_label(params[:author_id], "Author"), options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author", + placeholder: "Search authors", data: { any_user: "Any Author", first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: "author_id" } }) .filter-item.inline - = users_select_tag(:assignee_id, selected: params[:assignee_id], - placeholder: 'Assignee', class: 'trigger-submit', any_user: "Any Assignee", null_user: true, first_user: true, current_user: true) + - if params[:assignee_id] + = hidden_field_tag(:assignee_id, params[:assignee_id]) + = dropdown_tag(user_dropdown_label(params[:assignee_id], "Assignee"), options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee", + placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id" } }) .filter-item.inline.milestone-filter - = select_tag('milestone_title', projects_milestones_options, - class: 'select2 trigger-submit', include_blank: true, - data: {placeholder: 'Milestone'}) + - if params[:milestone_title] + = hidden_field_tag(:milestone_title, params[:milestone_title]) + = dropdown_tag(h(params[:milestone_name] || "Milestone"), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", + placeholder: "Search milestones", footer_content: true, data: { show_no: true, show_any: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: (@project.id if @project), milestones: (namespace_project_milestones_path(@project.namespace, @project, :js) if @project) } }) do + - if @project + %ul.dropdown-footer-list + - if can? current_user, :admin_milestone, @project + %li + = link_to new_namespace_project_milestone_path(@project.namespace, @project), title: "New Milestone" do + Create new + %li + = link_to namespace_project_milestones_path(@project.namespace, @project) do + - if can? current_user, :admin_milestone, @project + Manage milestones + - else + View milestones .filter-item.inline.labels-filter - = select_tag('label_name', projects_labels_options, - class: 'select2 trigger-submit', include_blank: true, - data: {placeholder: 'Label'}) + - if params[:label_name] + = hidden_field_tag(:label_name, params[:label_name]) + .dropdown + %button.dropdown-menu-toggle.js-label-select.js-filter-submit{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: (@project.id if @project), labels: (namespace_project_labels_path(@project.namespace, @project, :js) if @project)}} + %span.dropdown-toggle-text + = h(params[:label_name] || "Label") + = icon('chevron-down') + .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable + .dropdown-page-one + = dropdown_title("Filter by label") + = dropdown_filter("Search labels") + = dropdown_content + - if @project + = dropdown_footer do + %ul.dropdown-footer-list + - if can? current_user, :admin_label, @project + %li + %a.dropdown-toggle-page{href: "#"} + Create new + %li + = link_to namespace_project_labels_path(@project.namespace, @project) do + - if can? current_user, :admin_label, @project + Manage labels + - else + View labels + - if can? current_user, :admin_label, @project + .dropdown-page-two + = dropdown_title("Create new label", back: true) + = dropdown_content do + %input#new_label_color{type: "hidden"} + %input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"} + .dropdown-label-color-preview.js-dropdown-label-color-preview + .suggest-colors.suggest-colors-dropdown + - suggested_colors.each do |color| + = link_to '#', style: "background-color: #{color}", data: { color: color } do +   + %button.btn.btn-primary.js-new-label-btn{type: "button"} + Create + = dropdown_loading + .dropdown-loading + = icon('spinner spin') .pull-right = render 'shared/sort_dropdown' @@ -54,18 +86,32 @@ .issues_bulk_update.hide = form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do .filter-item.inline - = select_tag('update[state_event]', options_for_select([['Open', 'reopen'], ['Closed', 'close']]), include_blank: true, data: { placeholder: "Status" }) + = dropdown_tag("Status", options: { toggle_class: "js-issue-status", title: "Change status", dropdown_class: "dropdown-menu-selectable", data: { field_name: "update[state_event]" } } ) do + %ul + %li + %a{href: "#", data: {id: "reopen"}} Open + %li + %a{href: "#", data: {id: "close"}} Closed .filter-item.inline - = users_select_tag('update[assignee_id]', placeholder: 'Assignee', null_user: true, first_user: true, current_user: true) + = dropdown_tag("Assignee", options: { toggle_class: "js-user-search", title: "Assign to", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable", + placeholder: "Search authors", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: @project.id, field_name: "update[assignee_id]" } }) .filter-item.inline - = select_tag('update[milestone_id]', bulk_update_milestone_options, include_blank: true, data: { placeholder: "Milestone" }) + = dropdown_tag("Milestone", options: { title: "Assign milestone", toggle_class: 'js-milestone-select', filter: true, dropdown_class: "dropdown-menu-selectable", + placeholder: "Search milestones", data: { show_no: true, field_name: "update[milestone_id]", project_id: @project.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :js), use_id: true } }) = hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag :state_event, params[:state_event] .filter-item.inline = button_tag "Update issues", class: "btn update_selected_issues btn-save" +- if @label + .gray-content-block.second-block + = render "shared/label_row", label: @label + :javascript new UsersSelect(); + new LabelsSelect(); + new MilestoneSelect(); + new IssueStatusSelect(); $('form.filter-form').on('submit', function (event) { event.preventDefault(); Turbolinks.visit(this.action + '&' + $(this).serialize()); diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 90dc0062481..9ef729e960c 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -9,7 +9,7 @@ = f.label :title, class: 'control-label' .col-sm-10 = f.text_field :title, maxlength: 255, autofocus: true, autocomplete: 'off', - class: 'form-control pad js-gfm-input js-quick-submit', required: true + class: 'form-control pad js-gfm-input', required: true - if issuable.is_a?(MergeRequest) %p.help-block @@ -25,10 +25,19 @@ = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do = render 'projects/zen', f: f, attr: :description, - classes: 'description form-control js-quick-submit' + classes: 'description form-control' = render 'projects/notes/hints' .clearfix .error-alert + +- if issuable.is_a?(Issue) && !issuable.project.private? + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :confidential do + = f.check_box :confidential + This issue is confidential and should only be visible to team members + - if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project) %hr .form-group diff --git a/app/views/shared/issuable/_nav.html.haml b/app/views/shared/issuable/_nav.html.haml new file mode 100644 index 00000000000..a6970b7eebb --- /dev/null +++ b/app/views/shared/issuable/_nav.html.haml @@ -0,0 +1,25 @@ +%ul.nav-links.issues-state-filters + - if defined?(type) && type == :merge_requests + - page_context_word = 'merge requests' + - else + - page_context_word = 'issues' + %li{class: ("active" if params[:state] == 'opened')} + = link_to page_filter_path(state: 'opened'), title: "Filter by #{page_context_word} that are currently opened." do + #{state_filters_text_for(:opened, @project)} + + - if defined?(type) && type == :merge_requests + %li{class: ("active" if params[:state] == 'merged')} + = link_to page_filter_path(state: 'merged'), title: 'Filter by merge requests that are currently merged.' do + #{state_filters_text_for(:merged, @project)} + + %li{class: ("active" if params[:state] == 'closed')} + = link_to page_filter_path(state: 'closed'), title: 'Filter by merge requests that are currently closed and unmerged.' do + #{state_filters_text_for(:closed, @project)} + - else + %li{class: ("active" if params[:state] == 'closed')} + = link_to page_filter_path(state: 'closed'), title: 'Filter by issues that are currently closed.' do + #{state_filters_text_for(:closed, @project)} + + %li{class: ("active" if params[:state] == 'all')} + = link_to page_filter_path(state: 'all'), title: "Show all #{page_context_word}." do + #{state_filters_text_for(:all, @project)} diff --git a/app/views/shared/issuable/_participants.html.haml b/app/views/shared/issuable/_participants.html.haml index da6bacbb74a..f1d92ef48b2 100644 --- a/app/views/shared/issuable/_participants.html.haml +++ b/app/views/shared/issuable/_participants.html.haml @@ -1,5 +1,10 @@ .block.participants - .title + .sidebar-collapsed-icon + = icon('users') + %span + = participants.count + .title.hide-collapsed = pluralize participants.count, "participant" - participants.each do |participant| - = link_to_member(@project, participant, name: false, size: 24) + %span.hide-collapsed + = link_to_member(@project, participant, name: false, size: 24) diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml index 3a5ad00aa91..afad48499b7 100644 --- a/app/views/shared/issuable/_search_form.html.haml +++ b/app/views/shared/issuable/_search_form.html.haml @@ -1,9 +1,8 @@ -= form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do - .append-right-10.hidden-xs.hidden-sm - = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input', spellcheck: false } - = hidden_field_tag :state, params['state'] - = hidden_field_tag :scope, params['scope'] - = hidden_field_tag :assignee_id, params['assignee_id'] - = hidden_field_tag :author_id, params['author_id'] - = hidden_field_tag :milestone_id, params['milestone_id'] - = hidden_field_tag :label_id, params['label_id'] += form_tag(path, method: :get, id: "issue_search_form", class: 'issue-search-form') do + = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input input-short', spellcheck: false } + = hidden_field_tag :state, params['state'] + = hidden_field_tag :scope, params['scope'] + = hidden_field_tag :assignee_id, params['assignee_id'] + = hidden_field_tag :author_id, params['author_id'] + = hidden_field_tag :milestone_id, params['milestone_id'] + = hidden_field_tag :label_id, params['label_id'] diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 79c5cc7f40a..23b1ed1e51b 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -1,83 +1,128 @@ -.issuable-sidebar.issuable-affix - = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| - .block.assignee - .title - %label - Assignee - - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - .pull-right - = link_to 'Edit', '#', class: 'edit-link' - .value - - if issuable.assignee - %strong= link_to_member(@project, issuable.assignee, size: 24) +%aside.right-sidebar{ class: sidebar_gutter_collapsed_class } + .issuable-sidebar + .block + %span.issuable-count.hide-collapsed.pull-left + = issuable.iid + of + = issuables_count(issuable) + %span.pull-right + %a.gutter-toggle.js-sidebar-toggle{href: '#'} + = sidebar_gutter_toggle_icon + .issuable-nav.hide-collapsed.pull-right.btn-group{role: 'group', "aria-label" => '...'} + - if prev_issuable = prev_issuable_for(issuable) + = link_to 'Prev', [@project.namespace.becomes(Namespace), @project, prev_issuable], class: 'btn btn-default prev-btn' + - else + %a.btn.btn-default.disabled{href: '#'} + Prev + - if next_issuable = next_issuable_for(issuable) + = link_to 'Next', [@project.namespace.becomes(Namespace), @project, next_issuable], class: 'btn btn-default next-btn' - else - .light None + %a.btn.btn-default.disabled{href: '#'} + Next - .selectbox - = users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true, current_user: true, first_user: true) + = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| + .block.assignee + .sidebar-collapsed-icon + - if issuable.assignee + = link_to_member_avatar(issuable.assignee, size: 24) + - else + = icon('user') + .title.hide-collapsed + %label + Assignee + - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) + .pull-right + = link_to 'Edit', '#', class: 'edit-link' + .value.hide-collapsed + - if issuable.assignee + %strong= link_to_member(@project, issuable.assignee, size: 24) + - if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee) + %a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'} + = icon('exclamation-triangle') + - else + .light None - .block.milestone - .title - %label - Milestone - - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - .pull-right - = link_to 'Edit', '#', class: 'edit-link' - .value - - if issuable.milestone - %span.back-to-milestone - = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do - %strong - = icon('clock-o') - = issuable.milestone.title - - else - .light None - .selectbox - = f.select(:milestone_id, milestone_options(issuable), { include_blank: true }, { class: 'select2 select2-compact js-select2 js-milestone', data: { placeholder: 'Select milestone' }}) - = hidden_field_tag :issuable_context - = f.submit class: 'btn hide' + .selectbox.hide-collapsed + = users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true, current_user: true, first_user: true) - - if issuable.project.labels.any? - .block - .title - %label Labels + .block.milestone + .sidebar-collapsed-icon + = icon('clock-o') + %span + - if issuable.milestone + = issuable.milestone.title + - else + No + .title.hide-collapsed + %label + Milestone - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) .pull-right = link_to 'Edit', '#', class: 'edit-link' - .value.issuable-show-labels - - if issuable.labels.any? - - issuable.labels.each do |label| - = link_to_label(label) + .value.hide-collapsed + - if issuable.milestone + %span.back-to-milestone + = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do + %strong + = icon('clock-o') + = issuable.milestone.title - else .light None - .selectbox - = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, - { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" } + .selectbox.hide-collapsed + = f.select(:milestone_id, milestone_options(issuable), { include_blank: true }, { class: 'select2 select2-compact js-select2 js-milestone', data: { placeholder: 'Select milestone' }}) + = hidden_field_tag :issuable_context + = f.submit class: 'btn hide' - .block - .title - Cross-project reference - .cross-project-reference - %span#cross-project-reference - = cross_project_reference(@project, issuable) - = clipboard_button(clipboard_target: 'span#cross-project-reference') + - if issuable.project.labels.any? + .block.labels + .sidebar-collapsed-icon + = icon('tags') + %span + = issuable.labels.count + .title.hide-collapsed + %label Labels + - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) + .pull-right + = link_to 'Edit', '#', class: 'edit-link' + .value.issuable-show-labels.hide-collapsed + - if issuable.labels.any? + - issuable.labels.each do |label| + = link_to_label(label, type: issuable.to_ability_name) + - else + .light None + .selectbox.hide-collapsed + = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, + { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" } - = render "shared/issuable/participants", participants: issuable.participants(current_user) + = render "shared/issuable/participants", participants: issuable.participants(current_user) + %hr + - if current_user + - subscribed = issuable.subscribed?(current_user) + .block.light.subscription{data: {url: toggle_subscription_path(issuable)}} + .sidebar-collapsed-icon + = icon('rss') + .title.hide-collapsed + %label.light Notifications + - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed' + %button.btn.btn-block.btn-gray.subscribe-button.hide-collapsed{:type => 'button'} + %span= subscribed ? 'Unsubscribe' : 'Subscribe' + .subscription-status.hide-collapsed{data: {status: subscribtion_status}} + .unsubscribed{class: ( 'hidden' if subscribed )} + You're not receiving notifications from this thread. + .subscribed{class: ( 'hidden' unless subscribed )} + You're receiving notifications because you're subscribed to this thread. - - if current_user - - subscribed = issuable.subscribed?(current_user) - .block.light - .title - %label.light Notifications - - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed' - %button.btn.btn-block.btn-gray.subscribe-button{:type => 'button'} - %span= subscribed ? 'Unsubscribe' : 'Subscribe' - .subscription-status{data: {status: subscribtion_status}} - .unsubscribed{class: ( 'hidden' if subscribed )} - You're not receiving notifications from this thread. - .subscribed{class: ( 'hidden' unless subscribed )} - You're receiving notifications because you're subscribed to this thread. + - project_ref = cross_project_reference(@project, issuable) + .block.project-reference + .sidebar-collapsed-icon + = clipboard_button(clipboard_text: project_ref) + .cross-project-reference.hide-collapsed + %span + Reference: + %cite{title: project_ref} + = project_ref + = clipboard_button(clipboard_text: project_ref) - :javascript - new Subscription("#{toggle_subscription_path(issuable)}"); - new IssuableContext(); + :javascript + new Subscription('.subscription'); + new IssuableContext(); diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml new file mode 100644 index 00000000000..85888096722 --- /dev/null +++ b/app/views/shared/milestones/_issuable.html.haml @@ -0,0 +1,27 @@ +-# @project is present when viewing Project's milestone +- project = @project || issuable.project +- assignee = issuable.assignee +- issuable_type = issuable.class.table_name +- base_url_args = [project.namespace.becomes(Namespace), project, issuable_type] + +%li{ id: dom_id(issuable, 'sortable'), class: "issuable-row", 'data-iid' => issuable.iid, 'data-url' => polymorphic_path(issuable) } + %span + - if show_project_name + %strong #{project.name} · + - elsif show_full_project_name + %strong #{project.name_with_namespace} · + - if issuable.is_a?(Issue) + = confidential_icon(issuable) + = link_to_gfm issuable.title, [project.namespace.becomes(Namespace), project, issuable], title: issuable.title + %div{class: 'issuable-detail'} + = link_to [project.namespace.becomes(Namespace), project, issuable] do + %span{ class: 'issuable-number' }>= issuable.to_reference + + - issuable.labels.each do |label| + = link_to polymorphic_path(base_url_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' }) do + - render_colored_label(label) + + - if assignee + = link_to polymorphic_path(base_url_args, { milestone_title: @milestone.title, assignee_id: issuable.assignee_id, state: 'all' }), + class: 'has_tooltip', data: { 'original-title' => "Assigned to #{sanitize(assignee.name)}", container: 'body' } do + - image_tag(avatar_icon(issuable.assignee, 16), class: "avatar s16", alt: '') diff --git a/app/views/shared/milestones/_issuables.html.haml b/app/views/shared/milestones/_issuables.html.haml new file mode 100644 index 00000000000..8619939dde7 --- /dev/null +++ b/app/views/shared/milestones/_issuables.html.haml @@ -0,0 +1,16 @@ +- show_counter = local_assigns.fetch(:show_counter, false) +- primary = local_assigns.fetch(:primary, false) +- panel_class = primary ? 'panel-primary' : 'panel-default' + +.panel{ class: panel_class } + .panel-heading + = title + - if show_counter + .pull-right= issuables.size + + - class_prefix = dom_class(issuables).pluralize + %ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id } + = render partial: 'shared/milestones/issuable', + collection: issuables.sort_by(&:position), + as: :issuable, + locals: { show_project_name: show_project_name, show_full_project_name: show_full_project_name } diff --git a/app/views/shared/milestones/_issues_tab.html.haml b/app/views/shared/milestones/_issues_tab.html.haml new file mode 100644 index 00000000000..a8db7f8a556 --- /dev/null +++ b/app/views/shared/milestones/_issues_tab.html.haml @@ -0,0 +1,10 @@ +- args = { show_project_name: local_assigns.fetch(:show_project_name, false), + show_full_project_name: local_assigns.fetch(:show_full_project_name, false) } + +.row.prepend-top-default + .col-md-4 + = render 'shared/milestones/issuables', args.merge(title: 'Unstarted Issues (open and unassigned)', issuables: issues.opened.unassigned, id: 'unassigned', show_counter: true) + .col-md-4 + = render 'shared/milestones/issuables', args.merge(title: 'Ongoing Issues (open and assigned)', issuables: issues.opened.assigned, id: 'ongoing', show_counter: true) + .col-md-4 + = render 'shared/milestones/issuables', args.merge(title: 'Completed Issues (closed)', issuables: issues.closed, id: 'closed', show_counter: true) diff --git a/app/views/shared/milestones/_labels_tab.html.haml b/app/views/shared/milestones/_labels_tab.html.haml new file mode 100644 index 00000000000..ba27bafd1bc --- /dev/null +++ b/app/views/shared/milestones/_labels_tab.html.haml @@ -0,0 +1,18 @@ +%ul.bordered-list.manage-labels-list + - labels.each do |label| + - options = { milestone_title: @milestone.title, label_name: label.title } + + %li + %span.label-row + = link_to milestones_label_path(options) do + - render_colored_label(label) + %span.prepend-left-10 + = markdown(label.description, pipeline: :single_line) + + .pull-right + %strong.issues-count + = link_to milestones_label_path(options.merge(state: 'opened')) do + - pluralize milestone_issues_by_label_count(@milestone, label, state: :opened), 'open issue' + %strong.issues-count + = link_to milestones_label_path(options.merge(state: 'closed')) do + - pluralize milestone_issues_by_label_count(@milestone, label, state: :closed), 'closed issue' diff --git a/app/views/shared/milestones/_merge_requests_tab.haml b/app/views/shared/milestones/_merge_requests_tab.haml new file mode 100644 index 00000000000..c29d8ee6737 --- /dev/null +++ b/app/views/shared/milestones/_merge_requests_tab.haml @@ -0,0 +1,12 @@ +- args = { show_project_name: local_assigns.fetch(:show_project_name, false), + show_full_project_name: local_assigns.fetch(:show_full_project_name, false) } + +.row.prepend-top-default + .col-md-3 + = render 'shared/milestones/issuables', args.merge(title: 'Work in progress (open and unassigned)', issuables: merge_requests.opened.unassigned, id: 'unassigned') + .col-md-3 + = render 'shared/milestones/issuables', args.merge(title: 'Waiting for merge (open and assigned)', issuables: merge_requests.opened.assigned, id: 'ongoing') + .col-md-3 + = render 'shared/milestones/issuables', args.merge(title: 'Rejected (closed)', issuables: merge_requests.closed, id: 'closed') + .col-md-3 + = render 'shared/milestones/issuables', args.merge(title: 'Merged', issuables: merge_requests.merged, id: 'merged', primary: true) diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml new file mode 100644 index 00000000000..6b25745c554 --- /dev/null +++ b/app/views/shared/milestones/_milestone.html.haml @@ -0,0 +1,45 @@ +- dashboard = local_assigns[:dashboard] +- custom_dom_id = dom_id(@project ? milestone : milestone.milestones.first) + +%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: custom_dom_id } + .row + .col-sm-6 + %strong= link_to_gfm truncate(milestone.title, length: 100), milestone_path + .col-sm-6 + .pull-right.light #{milestone.percent_complete(current_user)}% complete + .row + .col-sm-6 + = link_to pluralize(milestone.issues_visible_to_user(current_user).size, 'Issue'), issues_path + · + = link_to pluralize(milestone.merge_requests.size, 'Merge Request'), merge_requests_path + .col-sm-6= milestone_progress_bar(milestone) + - if milestone.is_a?(GlobalMilestone) + .row + .col-sm-6 + .expiration= render('shared/milestone_expired', milestone: milestone) + .projects + - milestone.milestones.each do |milestone| + = link_to milestone_path(milestone) do + %span.label.label-gray + = dashboard ? milestone.project.name_with_namespace : milestone.project.name + - if @group + .col-sm-6 + - if can?(current_user, :admin_milestones, @group) + - if milestone.closed? + = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-xs btn-grouped btn-reopen" + - else + = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-xs btn-close" + + - if @project + .row + .col-sm-6= render('shared/milestone_expired', milestone: milestone) + .col-sm-6 + - if can?(current_user, :admin_milestone, milestone.project) and milestone.active? + = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs" do + = icon('pencil-square-o') + Edit + \ + = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close" + = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-xs btn-remove" do + = icon('trash-o') + Delete diff --git a/app/views/shared/milestones/_participants_tab.html.haml b/app/views/shared/milestones/_participants_tab.html.haml new file mode 100644 index 00000000000..67ae85ac276 --- /dev/null +++ b/app/views/shared/milestones/_participants_tab.html.haml @@ -0,0 +1,8 @@ +%ul.bordered-list + - users.each do |user| + %li + = link_to user, title: user.name, class: "darken" do + = image_tag avatar_icon(user, 32), class: "avatar s32" + %strong= truncate(user.name, lenght: 40) + %br + %small.cgray= user.username diff --git a/app/views/shared/milestones/_summary.html.haml b/app/views/shared/milestones/_summary.html.haml new file mode 100644 index 00000000000..385c6596606 --- /dev/null +++ b/app/views/shared/milestones/_summary.html.haml @@ -0,0 +1,28 @@ +- project = local_assigns[:project] + +.context.prepend-top-default + .milestone-summary + %h4 Progress + %strong= milestone.issues_visible_to_user(current_user).size + issues: + %span.milestone-stat + %strong= milestone.issues_visible_to_user(current_user).opened.size + open and + %strong= milestone.issues_visible_to_user(current_user).closed.size + closed + %span.milestone-stat + %strong== #{milestone.percent_complete(current_user)}% + complete + + %span.milestone-stat + %span.remaining-days= milestone_remaining_days(milestone) + %span.pull-right.tab-issues-buttons + - if project && can?(current_user, :create_issue, project) + = link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "btn btn-grouped", title: "New Issue" do + %i.fa.fa-plus + New Issue + = link_to 'Browse Issues', milestones_browse_issuables_path(milestone, type: :issues), class: "btn btn-grouped" + %span.pull-right.tab-merge-requests-buttons.hidden + = link_to 'Browse Merge Requests', milestones_browse_issuables_path(milestone, type: :merge_requests), class: "btn btn-grouped" + + = milestone_progress_bar(milestone) diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml new file mode 100644 index 00000000000..2b6ce2d7e7a --- /dev/null +++ b/app/views/shared/milestones/_tabs.html.haml @@ -0,0 +1,30 @@ +%ul.nav-links.no-top.no-bottom + %li.active + = link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do + Issues + %span.badge= milestone.issues_visible_to_user(current_user).size + %li + = link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do + Merge Requests + %span.badge= milestone.merge_requests.size + %li + = link_to '#tab-participants', 'data-toggle' => 'tab' do + Participants + %span.badge= milestone.participants.count + %li + = link_to '#tab-labels', 'data-toggle' => 'tab' do + Labels + %span.badge= milestone.labels.count + +- show_project_name = local_assigns.fetch(:show_project_name, false) +- show_full_project_name = local_assigns.fetch(:show_full_project_name, false) + +.tab-content.milestone-content + .tab-pane.active#tab-issues + = render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user), show_project_name: show_project_name, show_full_project_name: show_full_project_name + .tab-pane#tab-merge-requests + = render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name + .tab-pane#tab-participants + = render 'shared/milestones/participants_tab', users: milestone.participants + .tab-pane#tab-labels + = render 'shared/milestones/labels_tab', labels: milestone.labels diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml new file mode 100644 index 00000000000..cab8743a077 --- /dev/null +++ b/app/views/shared/milestones/_top.html.haml @@ -0,0 +1,58 @@ +- page_title milestone.title, "Milestones" + +- group = local_assigns[:group] + +.detail-page-header + .status-box{ class: "status-box-#{milestone.closed? ? 'closed' : 'open'}" } + - if milestone.closed? + Closed + - elsif milestone.expired? + Expired + - else + Open + %span.identifier + Milestone #{milestone.title} + - if milestone.expires_at + %span.creator + · + = milestone.expires_at + - if group + .pull-right + - if can?(current_user, :admin_milestones, group) + - if milestone.active? + = link_to 'Close Milestone', group_milestone_path(group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close" + - else + = link_to 'Reopen Milestone', group_milestone_path(group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen" + +.detail-page-description.gray-content-block.second-block + %h2.title + = markdown escape_once(milestone.title), pipeline: :single_line + +- if milestone.complete?(current_user) && milestone.active? + .alert.alert-success.prepend-top-default + - close_msg = group ? 'You may close the milestone now.' : 'Navigate to the project to close the milestone.' + %span All issues for this milestone are closed. #{close_msg} + +.table-holder + %table.table + %thead + %tr + %th Project + %th Open issues + %th State + %th Due date + - milestone.milestones.each do |ms| + %tr + %td + - project_name = group ? ms.project.name : ms.project.name_with_namespace + = link_to project_name, namespace_project_milestone_path(ms.project.namespace, ms.project, ms) + %td + = ms.issues_visible_to_user(current_user).opened.count + %td + - if ms.closed? + Closed + - else + Open + %td + = ms.expires_at + diff --git a/app/views/shared/projects/_dropdown.html.haml b/app/views/shared/projects/_dropdown.html.haml new file mode 100644 index 00000000000..e7e04621ff4 --- /dev/null +++ b/app/views/shared/projects/_dropdown.html.haml @@ -0,0 +1,22 @@ +- @sort ||= sort_value_recently_updated +- archived = params[:archived] +.dropdown.inline + %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} + %span.light + = projects_sort_options_hash[@sort] + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable + %li.dropdown-header + Sort by + - projects_sort_options_hash.each do |value, title| + %li + = link_to filter_projects_path(sort: value, archived: archived), class: ("is-active" if @sort == value) do + = title + + %li.divider + %li + = link_to filter_projects_path(sort: @sort, archived: nil), class: ("is-active" unless params[:archived].present?) do + Hide archived projects + %li + = link_to filter_projects_path(sort: @sort, archived: true), class: ("is-active" if params[:archived].present?) do + Show archived projects diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index e5ffe1e29ae..2e08bb2ac08 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -1,21 +1,24 @@ - projects_limit = 20 unless local_assigns[:projects_limit] - avatar = true unless local_assigns[:avatar] == false +- use_creator_avatar = false unless local_assigns[:use_creator_avatar] == true - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true +- remote = false unless local_assigns[:remote] == true -%ul.projects-list - - projects.each_with_index do |project, i| - - css_class = (i >= projects_limit) ? 'hide' : nil - = render "shared/projects/project", project: project, skip_namespace: skip_namespace, - avatar: avatar, stars: stars, css_class: css_class, ci: ci - - - if projects.size > projects_limit - %li.bottom.center - .light - #{projects_limit} of #{pluralize(projects.count, 'project')} displayed. - = link_to '#', class: 'js-expand' do - Show all +.projects-list-holder + - if projects.any? + %ul.projects-list.content-list + - projects.each_with_index do |project, i| + - css_class = (i >= projects_limit) ? 'hide' : nil + = render "shared/projects/project", project: project, skip_namespace: skip_namespace, + avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar, + forks: forks, show_last_commit_as_description: show_last_commit_as_description + = paginate(projects, remote: remote, theme: "gitlab") if projects.respond_to? :total_pages + - else + .nothing-here-block No projects found :javascript - new ProjectsList(); + ProjectsList.init(); diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 86249851a82..97cfb76cdb0 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -1,16 +1,25 @@ - avatar = true unless local_assigns[:avatar] == false - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true - css_class = '' unless local_assigns[:css_class] -- css_class += " no-description" unless project.description.present? +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && project.commit +- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description +- ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit +- cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] +- cache_key.push(ci_commit.status) if ci_commit + %li.project-row{ class: css_class } - = cache [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] do + = cache(cache_key) do = link_to project_path(project), class: dom_class(project) do - if avatar .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar project-avatar s46') - %span.project-full-name + - if use_creator_avatar + = image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:'' + - else + = project_icon(project, alt: '', class: 'avatar project-avatar s40') + %span.project-full-name.title %span.namespace-name - if project.namespace && !skip_namespace = project.namespace.human_name @@ -18,15 +27,28 @@ %span.project-name.filter-title = project.name - .project-controls - - if ci && !project.empty_repo? && project.commit - - if ci_commit = project.ci_commit(project.commit.sha) + .controls + - if project.main_language + %span + = project.main_language + - if ci_commit + %span = render_ci_status(ci_commit) - + - if forks + %span + = icon('code-fork') + = project.forks_count - if stars %span - %i.fa.fa-star + = icon('star') = project.star_count - - if project.description.present? - .project-description + %span.visibility-icon.has_tooltip{data: { container: 'body', placement: 'left' }, + title: "#{visibility_level_label(project.visibility_level)} - #{project_visibility_level_description(project.visibility_level)}"} + = visibility_level_icon(project.visibility_level, fw: false) + - if show_last_commit_as_description + .description + = link_to_gfm project.commit.title, namespace_project_commit_path(project.namespace, project, project.commit), + class: "commit-row-message" + - elsif project.description.present? + .description = markdown(project.description, pipeline: :description) diff --git a/app/views/shared/snippets/_blob.html.haml b/app/views/shared/snippets/_blob.html.haml index d26a99bb14c..773ce8ac240 100644 --- a/app/views/shared/snippets/_blob.html.haml +++ b/app/views/shared/snippets/_blob.html.haml @@ -1,10 +1,11 @@ - unless @snippet.content.empty? - if markup?(@snippet.file_name) + %textarea.markdown-snippet-copy.blob-content{data: {blob_id: @snippet.id}} + = @snippet.data .file-content.wiki = render_markup(@snippet.file_name, @snippet.data) - else - .file-content.code - = render 'shared/file_highlight', blob: @snippet + = render 'shared/file_highlight', blob: @snippet - else .file-content.code .nothing-here-block Empty file diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml index c6294caddc7..a316a085107 100644 --- a/app/views/shared/snippets/_snippet.html.haml +++ b/app/views/shared/snippets/_snippet.html.haml @@ -1,10 +1,12 @@ %li.snippet-row + = image_tag avatar_icon(snippet.author_email), class: "avatar s40 hidden-xs", alt: '' + .snippet-title - = link_to reliable_snippet_path(snippet) do + = link_to reliable_snippet_path(snippet), class: 'title' do = truncate(snippet.title, length: 60) - if snippet.private? %span.label.label-gray - %i.fa.fa-lock + = icon('lock') private %span.monospace.pull-right = snippet.file_name @@ -15,6 +17,5 @@ .snippet-info = link_to user_snippets_path(snippet.author) do - = image_tag avatar_icon(snippet.author_email), class: "avatar s24", alt: '' = snippet.author_name authored #{time_ago_with_tooltip(snippet.created_at)} |