Commit 4fb53402 authored by Dennis Tang's avatar Dennis Tang
Browse files

Refresh group overview to match project overview

- Avatar, group name, and group description now left-aligned
- Notification setting and "New project" CTA right-aligned
  with group avatar and name
- Leave group / request access now a link next to the 'Group'
  label below the group name
- Notification setting label removed in favor of icons
  - Tooltip added to indicate notification setting
- Search option moved inside table header next to "Sort by"
parent 9961e6c99444
......@@ -278,8 +278,8 @@ $performance-bar-height: 35px;
$flash-height: 52px;
$context-header-height: 60px;
$breadcrumb-min-height: 48px;
$project-title-row-height: 64px;
$project-avatar-mobile-size: 24px;
$home-panel-title-row-height: 64px;
$home-panel-avatar-mobile-size: 24px;
$gl-line-height: 16px;
$gl-line-height-24: 24px;
$gl-line-height-14: 14px;
......
......@@ -29,9 +29,7 @@
}
}
.group-nav-container .group-search,
.group-nav-container .nav-controls {
display: flex;
align-items: flex-start;
padding: $gl-padding-top 0 0;
......@@ -44,6 +42,52 @@
margin-top: 0;
}
@include media-breakpoint-down(sm) {
.dropdown,
.dropdown .dropdown-toggle,
.btn-success {
display: block;
}
.group-filter-form,
.dropdown {
margin-bottom: 10px;
margin-right: 0;
}
&,
.group-filter-form,
.group-filter-form-field,
.dropdown,
.dropdown .dropdown-toggle,
.btn-success {
width: 100%;
}
.dropdown .dropdown-toggle .fa-chevron-down {
position: absolute;
top: 11px;
right: 8px;
}
}
}
.home-panel-buttons {
.home-panel-action-button {
vertical-align: top;
}
.notification-dropdown {
.dropdown-menu {
@extend .dropdown-menu-right;
}
.icon {
fill: $gl-text-color-secondary;
}
}
.new-project-subgroup {
.dropdown-primary {
min-width: 115px;
......@@ -99,61 +143,29 @@
font-weight: $gl-font-weight-bold;
}
}
}
}
@include media-breakpoint-down(sm) {
&,
.dropdown,
.dropdown .dropdown-toggle,
.btn-success {
display: block;
}
.group-filter-form,
.dropdown {
margin-bottom: 10px;
margin-right: 0;
}
.group-filter-form,
.dropdown .dropdown-toggle,
.btn-success {
width: 100%;
}
.dropdown .dropdown-toggle .fa-chevron-down {
position: absolute;
top: 11px;
right: 8px;
}
.new-project-subgroup {
display: flex;
align-items: flex-start;
@include media-breakpoint-down(sm) {
display: flex;
align-items: flex-start;
.dropdown-primary {
flex: 1;
}
.dropdown-primary {
flex: 1;
}
.dropdown-toggle {
width: auto;
}
.dropdown-toggle {
width: auto;
}
.dropdown-menu {
width: 100%;
max-width: inherit;
min-width: inherit;
.dropdown-menu {
width: 100%;
max-width: inherit;
min-width: inherit;
}
}
}
}
}
.group-nav-container .group-search {
padding: $gl-padding 0;
border-bottom: 1px solid $border-color;
}
.groups-listing {
.group-list-tree .group-row:first-child {
border-top: 0;
......
......@@ -140,73 +140,19 @@
}
}
.project-home-panel,
.group-home-panel {
padding-top: 24px;
padding-bottom: 24px;
.group-avatar {
float: none;
margin: 0 auto;
&.identicon {
border-radius: 50%;
}
}
.group-title {
margin-top: 10px;
margin-bottom: 10px;
font-size: 24px;
font-weight: $gl-font-weight-normal;
line-height: 1;
word-wrap: break-word;
.fa {
margin-left: 2px;
font-size: 12px;
vertical-align: middle;
}
}
.group-home-desc {
margin-left: auto;
margin-right: auto;
margin-bottom: 0;
max-width: 700px;
> p {
margin-bottom: 0;
}
}
.notifications-btn {
.fa-bell,
.fa-spinner {
margin-right: 6px;
}
.fa-angle-down {
margin-left: 6px;
}
}
}
.group-home-panel,
.project-home-panel {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
.project-avatar {
width: $project-title-row-height;
height: $project-title-row-height;
.home-panel-avatar {
width: $home-panel-title-row-height;
height: $home-panel-title-row-height;
flex-shrink: 0;
flex-basis: $project-title-row-height;
margin: 0 $gl-padding 0 0;
flex-basis: $home-panel-title-row-height;
}
.project-title {
margin-top: 8px;
margin-bottom: 5px;
.home-panel-title {
font-size: 20px;
line-height: $gl-line-height-24;
font-weight: bold;
......@@ -215,11 +161,7 @@
font-size: $gl-font-size-large;
}
.project-visibility {
color: $gl-text-color-secondary;
}
.project-topic-list {
.home-panel-topic-list {
font-size: $gl-font-size;
font-weight: $gl-font-weight-normal;
......@@ -231,12 +173,12 @@
}
}
.project-title-row {
.home-panel-title-row {
@include media-breakpoint-down(sm) {
.project-avatar {
width: $project-avatar-mobile-size;
height: $project-avatar-mobile-size;
flex-basis: $project-avatar-mobile-size;
.home-panel-avatar {
width: $home-panel-avatar-mobile-size;
height: $home-panel-avatar-mobile-size;
flex-basis: $home-panel-avatar-mobile-size;
.avatar {
font-size: 20px;
......@@ -244,28 +186,26 @@
}
}
.project-title {
.home-panel-title {
margin-top: 4px;
margin-bottom: 2px;
font-size: $gl-font-size;
line-height: $gl-font-size-large;
}
.project-topic-list,
.project-metadata {
.home-panel-topic-list,
.home-panel-metadata {
font-size: $gl-font-size-small;
}
}
}
.project-metadata {
.home-panel-metadata {
font-weight: normal;
font-size: 14px;
line-height: $gl-btn-line-height;
color: $gl-text-color-secondary;
.project-license {
.home-panel-license {
.btn {
line-height: 0;
border-width: 0;
......@@ -273,13 +213,13 @@
}
.access-request-link,
.project-topic-list {
.home-panel-topic-list {
padding-left: $gl-padding-8;
border-left: 1px solid $gl-text-color-secondary;
}
}
.project-description {
.home-panel-description {
@include media-breakpoint-up(md) {
font-size: $gl-font-size-large;
}
......@@ -292,12 +232,11 @@
}
}
.nav > .project-repo-buttons {
.nav > .project-buttons {
margin-top: 0;
}
.project-repo-buttons,
.group-buttons {
.project-repo-buttons {
.btn {
&:last-child {
margin-left: 0;
......@@ -318,8 +257,30 @@
margin-left: 0;
}
}
.notifications-icon {
top: 1px;
margin-right: 0;
}
}
.icon {
top: 0;
}
.count-badge,
.btn-xs {
height: 24px;
}
.dropdown-toggle,
.clone-dropdown-btn {
.fa {
color: unset;
}
}
.home-panel-action-button,
.project-action-button {
margin: $gl-padding $gl-padding-8 0 0;
vertical-align: top;
......@@ -385,31 +346,6 @@
}
}
.project-repo-buttons {
.icon {
top: 0;
}
.count-badge,
.btn-xs {
height: 24px;
}
.dropdown-toggle,
.clone-dropdown-btn {
.fa {
color: unset;
}
}
.btn {
.notifications-icon {
top: 1px;
margin-right: 0;
}
}
}
.split-one {
display: inline-table;
margin-right: 12px;
......@@ -772,9 +708,6 @@
.project-stats,
.project-buttons {
font-size: 0;
text-align: center;
.scrolling-tabs-container {
.scrolling-tabs {
margin-top: $gl-padding-8;
......
......@@ -17,7 +17,8 @@ def update
@saved = @notification_setting.update(notification_setting_params_for(@notification_setting.source))
if params[:hide_label].present?
render_response("projects/buttons/_notifications")
btn_class = params[:project_id].present? ? 'btn-xs' : ''
render_response("shared/notifications/_new_button", btn_class)
else
render_response
end
......@@ -41,9 +42,9 @@ def can_read?(resource)
can?(current_user, ability_name, resource)
end
def render_response(response_template = "shared/notifications/_button")
def render_response(response_template = "shared/notifications/_button", btn_class = nil)
render json: {
html: view_to_html_string(response_template, notification_setting: @notification_setting),
html: view_to_html_string(response_template, notification_setting: @notification_setting, btn_class: btn_class),
saved: @saved
}
end
......
.group-home-panel.text-center.border-bottom
%div{ class: container_class }
.avatar-container.s70.group-avatar
= group_icon(@group, class: "avatar s70 avatar-tile")
%h1.group-title
= @group.name
%span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false)
- can_create_subgroups = can?(current_user, :create_subgroup, @group)
- if @group.description.present?
.group-home-desc
= markdown_field(@group, :description)
.group-home-panel
.row.mb-3
.home-panel-title-row.col-md-12.col-lg-6.d-flex
.avatar-container.home-panel-avatar.append-right-default.float-none
= group_icon(@group, class: 'avatar avatar-tile s64', width: 64, height: 64)
.d-flex.flex-column.flex-wrap.align-items-baseline
.d-inline-flex.align-items-baseline
%h1.home-panel-title.prepend-top-8.append-bottom-5
= @group.name
%span.visibility-icon.text-secondary.prepend-left-4.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false, options: {class: 'icon'})
.home-panel-metadata.d-flex.align-items-center.text-secondary
%span
= _("Group")
- if current_user
%span.access-request-links.prepend-left-8
= render 'shared/members/access_request_links', source: @group
- if current_user
.group-buttons.d-none.d-sm-block
= render 'shared/members/access_request_buttons', source: @group
= render 'shared/notifications/button', notification_setting: @notification_setting
.home-panel-buttons.col-md-12.col-lg-6.d-inline-flex.flex-wrap.justify-content-lg-end
- if current_user
.group-buttons
= render 'shared/notifications/new_button', notification_setting: @notification_setting, btn_class: 'btn'
- if can? current_user, :create_projects, @group
- new_project_label = _("New project")
- new_subgroup_label = _("New subgroup")
- if can_create_subgroups
.btn-group.new-project-subgroup.droplab-dropdown.home-panel-action-button.prepend-top-default.js-new-project-subgroup.qa-new-project-or-subgroup-dropdown{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } }
%input.btn.btn-success.dropdown-primary.js-new-group-child.qa-new-in-group-button{ type: "button", value: new_project_label, data: { action: "new-project" } }
%button.btn.btn-success.dropdown-toggle.js-dropdown-toggle.qa-new-project-or-subgroup-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } }
= sprite_icon("arrow-down", css_class: "icon")
%ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } }
%li.droplab-item-selected.qa-new-project-option{ role: "button", data: { value: "new-project", text: new_project_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
.description
%strong= new_project_label
%span= s_("GroupsTree|Create a project in this group.")
%li.divider.droplap-item-ignore
%li.qa-new-subgroup-option{ role: "button", data: { value: "new-subgroup", text: new_subgroup_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
.description
%strong= new_subgroup_label
%span= s_("GroupsTree|Create a subgroup in this group.")
- else
= link_to new_project_label, new_project_path(namespace_id: @group.id), class: "btn btn-success"
- if @group.description.present?
.group-home-desc.mt-1
.home-panel-description
.home-panel-description-markdown.read-more-container
= markdown_field(@group, :description)
%button.btn.btn-blank.btn-link.js-read-more-trigger.d-lg-none{ type: "button" }
= _("Read more")
- @no_container = true
- breadcrumb_title _("Details")
- can_create_subgroups = can?(current_user, :create_subgroup, @group)
- @content_class = "limit-container-width" unless fluid_layout
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
= render 'groups/home_panel'
.groups-listing{ class: container_class, data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
.top-area.group-nav-container
.group-search
= render "shared/groups/search_form"
- if can? current_user, :create_projects, @group
- new_project_label = _("New project")
- new_subgroup_label = _("New subgroup")
- if can_create_subgroups
.btn-group.new-project-subgroup.droplab-dropdown.js-new-project-subgroup.qa-new-project-or-subgroup-dropdown{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } }
%input.btn.btn-success.dropdown-primary.js-new-group-child.qa-new-in-group-button{ type: "button", value: new_project_label, data: { action: "new-project" } }
%button.btn.btn-success.dropdown-toggle.js-dropdown-toggle.qa-new-project-or-subgroup-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } }
= icon("caret-down", class: "dropdown-btn-icon")
%ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } }
%li.droplab-item-selected.qa-new-project-option{ role: "button", data: { value: "new-project", text: new_project_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
.description
%strong= new_project_label
%span= s_("GroupsTree|Create a project in this group.")
%li.divider.droplap-item-ignore
%li.qa-new-subgroup-option{ role: "button", data: { value: "new-subgroup", text: new_subgroup_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
.description
%strong= new_subgroup_label
%span= s_("GroupsTree|Create a subgroup in this group.")
- else
= link_to new_project_label, new_project_path(namespace_id: @group.id), class: "btn btn-success"
.scrolling-tabs-container.inner-page-scroll-tabs
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
%ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs
%li.js-subgroups_and_projects-tab
= link_to group_path, data: { target: 'div#subgroups_and_projects', action: 'subgroups_and_projects', toggle: 'tab'} do
= _("Subgroups and projects")
%li.js-shared-tab
= link_to group_shared_path, data: { target: 'div#shared', action: 'shared', toggle: 'tab'} do
= _("Shared projects")
%li.js-archived-tab
= link_to group_archived_path, data: { target: 'div#archived', action: 'archived', toggle: 'tab'} do
= _("Archived projects")
.nav-controls
= render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
.tab-content
#subgroups_and_projects.tab-pane
= render "subgroups_and_projects", group: @group
#shared.tab-pane
= render "shared_projects", group: @group
#archived.tab-pane
= render "archived_projects", group: @group
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render 'groups/home_panel'
.groups-listing{ data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
.top-area.group-nav-container
.scrolling-tabs-container.inner-page-scroll-tabs
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
%ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs
%li.js-subgroups_and_projects-tab
= link_to group_path, data: { target: 'div#subgroups_and_projects', action: 'subgroups_and_projects', toggle: 'tab'} do
= _("Subgroups and projects")
%li.js-shared-tab
= link_to group_shared_path, data: { target: 'div#shared', action: 'shared', toggle: 'tab'} do
= _("Shared projects")
%li.js-archived-tab
= link_to group_archived_path, data: { target: 'div#archived', action: 'archived', toggle: 'tab'} do
= _("Archived projects")
.nav-controls.d-block.d-md-flex
.group-search
= render "shared/groups/search_form"
= render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
.tab-content
#subgroups_and_projects.tab-pane
= render "subgroups_and_projects", group: @group
#shared.tab-pane
= render "shared_projects", group: @group
#archived.tab-pane
= render "archived_projects", group: @group
- empty_repo = @project.empty_repo?
- show_auto_devops_callout = show_auto_devops_callout?(@project)
.project-home-panel{ class: ("empty-project" if empty_repo) }
.project-header.row.append-bottom-8
.project-title-row.col-md-12.col-lg-6.d-flex
.avatar-container.project-avatar.float-none
.row.append-bottom-8
.home-panel-title-row.col-md-12.col-lg-6.d-flex
.avatar-container.home-panel-avatar.append-right-default.float-none
= project_icon(@project, alt: @project.name, class: 'avatar avatar-tile s64', width: 64, height: 64)
.d-flex.flex-column.flex-wrap.align-items-baseline
.d-inline-flex.align-items-baseline
%h1.project-title.qa-project-name
%h1.home-panel-title.prepend-top-8.append-bottom-5.qa-project-name
= @project.name