Commit c7a4a3f9 authored by Takuya Noguchi's avatar Takuya Noguchi

Reduce page_bundle for TODO list

Improve user experience in terms of performance

Changelog: fixed
Co-authored-by: default avatarPhil Hughes <me@iamphill.com>
Signed-off-by: default avatarTakuya Noguchi <takninnovationresearch@gmail.com>
parent 7368e2a6
......@@ -8,8 +8,6 @@
.todos-list > .todo {
// workaround because we cannot use border-collapse
border-top: 1px solid transparent;
display: flex;
flex-direction: row;
&:hover {
background-color: var(--blue-50, $blue-50);
......@@ -26,25 +24,6 @@
}
}
.todo-avatar,
.todo-actions {
@include transition(opacity);
flex: 0 0 auto;
}
.todo-actions {
display: flex;
justify-content: center;
flex-direction: column;
margin-left: 10px;
min-width: 55px;
}
.todo-item {
flex: 0 1 100%;
min-width: 0;
}
&.todo-pending.done-reversible {
&:hover {
border-color: var(--border-color, $border-color);
......@@ -71,58 +50,22 @@
.todo-item {
@include transition(opacity);
.todo-title {
> .title-item {
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
.todo-label {
flex: 0 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.status-box {
margin: 0;
float: none;
display: inline-block;
font-weight: $gl-font-weight-normal;
padding: 0 5px;
line-height: inherit;
font-size: 14px;
}
.todo-label,
.todo-project {
a {
font-weight: $gl-font-weight-normal;
color: var(--blue-600, $blue-600);
}
}
.todo-body {
.badge.badge-pill,
p {
color: var(--gl-text-color, $gl-text-color);
}
.md {
color: $gl-grayish-blue;
font-size: $gl-font-size;
}
code {
white-space: pre-wrap;
}
pre {
border: 0;
background: var(--gray-50, $gray-50);
......@@ -139,120 +82,13 @@
float: none;
}
p:last-child {
margin-bottom: 0;
}
}
.gl-label-scoped {
--label-inset-border: inset 0 0 0 1px currentColor;
}
}
@include media-breakpoint-down(lg) {
.todos-filters {
.filter-categories {
width: 75%;
.filter-item {
margin-bottom: 10px;
}
.gl-label-scoped {
--label-inset-border: inset 0 0 0 1px currentColor;
}
}
}
@include media-breakpoint-down(sm) {
.container-fluid .todos-list-container {
margin: 0 (-$gl-padding);
}
.todo {
.avatar {
display: none;
}
}
.todo-item {
.todo-title {
margin-bottom: 10px;
.todo-label {
white-space: normal;
}
}
.todo-body {
margin: 0;
@include media-breakpoint-down(sm) {
border-left: 2px solid var(--border-color, $border-color);
padding-left: 10px;
}
}
.todos-filters {
.filter-categories {
width: auto;
}
.dropdown-menu-toggle {
width: 100%;
}
.dropdown-menu-toggle-sort {
width: auto;
}
}
}
.todos-empty {
display: flex;
flex-direction: column;
max-width: 900px;
margin-left: auto;
margin-right: auto;
@include media-breakpoint-up(sm) {
flex-direction: row;
padding-top: 80px;
}
}
.todos-empty-content {
align-self: center;
max-width: 480px;
}
.todos-empty-hero {
width: 200px;
margin-left: auto;
margin-right: auto;
@include media-breakpoint-up(sm) {
width: 300px;
margin-right: 0;
order: 2;
}
}
.todos-all-done {
padding-top: 20px;
@include media-breakpoint-up(sm) {
padding-top: 50px;
}
> svg {
display: block;
max-width: 300px;
margin: 0 auto 20px;
}
p {
max-width: 470px;
margin-left: auto;
margin-right: auto;
}
a {
font-weight: $gl-font-weight-bold;
}
}
......@@ -110,10 +110,8 @@ module TodosHelper
'alert'
end
content_tag(:span, nil, class: 'target-status') do
content_tag(:span, nil, class: "status-box status-box-#{type}-#{todo.target.state.to_s.dasherize}") do
todo.target.state.to_s.capitalize
end
tag.span class: "gl-my-0 gl-px-2 status-box status-box-#{type}-#{todo.target.state.to_s.dasherize}" do
todo.target.state.to_s.capitalize
end
end
......
%li{ class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo), data: { url: todo_target_path(todo) } }
.todo-avatar
= author_avatar(todo, size: 40)
.todo-item.todo-block.align-self-center{ data: { qa_selector: "todo_item_container" } }
.todo-title
- if todo_author_display?(todo)
= todo_target_state_pill(todo)
%span.title-item.author-name.bold
- if todo.author
= link_to_author(todo, self_added: todo.self_added?)
%li.todo{ class: "todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo), data: { url: todo_target_path(todo) } }
.gl-display-flex.gl-flex-direction-row
.todo-avatar.gl-display-none.gl-sm-display-inline-block
= author_avatar(todo, size: 40)
.todo-item.gl-w-full.gl-align-self-center{ data: { qa_selector: "todo_item_container" } }
.todo-title.gl-mb-3.gl-md-mb-0
- if todo_author_display?(todo)
= todo_target_state_pill(todo)
%span.title-item.author-name.bold
- if todo.author
= link_to_author(todo, self_added: todo.self_added?)
- else
(removed)
%span.title-item.action-name{ data: { qa_selector: "todo_action_name_content" } }
= todo_action_name(todo)
%span.title-item.todo-label.todo-target-link
- if todo.target
= todo_target_link(todo)
- else
(removed)
%span.title-item.action-name{ data: { qa_selector: "todo_action_name_content" } }
= todo_action_name(todo)
%span.title-item.todo-label.todo-target-link
- if todo.target
= todo_target_link(todo)
- else
= _("(removed)")
%span.title-item.todo-target-title{ data: { qa_selector: "todo_target_title_content" } }
= todo_target_title(todo)
%span.title-item.todo-project.todo-label
at
= todo_parent_path(todo)
- if todo.self_assigned?
%span.title-item.action-name
= todo_self_addressing(todo)
%span.title-item
&middot;
%span.title-item.todo-timestamp
#{time_ago_with_tooltip(todo.created_at)}
= todo_due_date(todo)
- if todo.note.present?
.todo-body
.todo-note.break-word
.md
= first_line_in_markdown(todo, :body, 150, project: todo.project)
- if todo.pending?
.todo-actions
= link_to dashboard_todo_path(todo), method: :delete, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-done-todo', data: { href: dashboard_todo_path(todo) } do
Done
%span.gl-spinner.ml-1
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do
Undo
%span.gl-spinner.ml-1
- else
.todo-actions
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
Add a to do
%span.gl-spinner.ml-1
= _("(removed)")
%span.title-item.todo-target-title{ data: { qa_selector: "todo_target_title_content" } }
= todo_target_title(todo)
%span.title-item.todo-project.todo-label
at
= todo_parent_path(todo)
- if todo.self_assigned?
%span.title-item.action-name
= todo_self_addressing(todo)
%span.title-item
&middot;
%span.title-item.todo-timestamp
#{time_ago_with_tooltip(todo.created_at)}
= todo_due_date(todo)
- if todo.note.present?
.todo-body
.todo-note.break-word
.md
= first_line_in_markdown(todo, :body, 150, project: todo.project)
.todo-actions.gl-ml-3
- if todo.pending?
= link_to dashboard_todo_path(todo), method: :delete, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-done-todo', data: { href: dashboard_todo_path(todo) } do
Done
%span.gl-spinner.ml-1
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do
Undo
%span.gl-spinner.ml-1
- else
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
Add a to do
%span.gl-spinner.ml-1
......@@ -36,34 +36,34 @@
.todos-filters
.issues-details-filters.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form d-sm-flex' do
.filter-categories.flex-fill
.filter-item.inline
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row' do
.filter-categories.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-flex-fill-1.gl-flex-wrap.gl-mx-n2
.filter-item.gl-m-2
- if params[:group_id].present?
= hidden_field_tag(:group_id, params[:group_id])
= dropdown_tag(group_dropdown_label(params[:group_id], 'Group'), options: { toggle_class: 'js-group-search js-filter-submit', title: 'Filter by group', filter: true, filterInput: 'input#group-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-group js-filter-submit',
= dropdown_tag(group_dropdown_label(params[:group_id], 'Group'), options: { toggle_class: 'js-group-search js-filter-submit gl-xs-w-full!', title: 'Filter by group', filter: true, filterInput: 'input#group-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-group js-filter-submit',
placeholder: 'Search groups', data: { default_label: 'Group', display: 'static' } })
.filter-item.inline
.filter-item.gl-m-2
- if params[:project_id].present?
= hidden_field_tag(:project_id, params[:project_id])
= dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
= dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit gl-xs-w-full!', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: 'Search projects', data: { default_label: 'Project', display: 'static' } })
.filter-item.inline
.filter-item.gl-m-2
- if params[:author_id].present?
= 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, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
= dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search gl-xs-w-full!', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author', todo_filter: true, todo_state_filter: params[:state] || 'pending' } })
.filter-item.inline
.filter-item.gl-m-2
- if params[:type].present?
= hidden_field_tag(:type, params[:type])
= dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit',
= dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit gl-xs-w-full!', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit',
data: { data: todo_types_options, default_label: 'Type' } })
.filter-item.inline.actions-filter
.filter-item.actions-filter.gl-m-2
- if params[:action_id].present?
= hidden_field_tag(:action_id, params[:action_id])
= dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit',
= dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit gl-xs-w-full!', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit',
data: { data: todo_actions_options, default_label: 'Action' } })
.filter-item.sort-filter
.filter-item.sort-filter.gl-mt-3.gl-sm-mt-0.gl-mb-0.gl-sm-mb-0
.dropdown
%button.dropdown-menu-toggle.dropdown-menu-toggle-sort{ type: 'button', class: 'gl-xs-w-full!', 'data-toggle' => 'dropdown' }
%span.light
......@@ -81,40 +81,45 @@
= link_to todos_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
.todos-list-container.js-todos-all
.row.js-todos-all
- if @todos.any?
.js-todos-list-container{ data: { qa_selector: "todos_list_container" } }
.col.js-todos-list-container{ data: { qa_selector: "todos_list_container" } }
.js-todos-options{ data: { per_page: @todos.limit_value, current_page: @todos.current_page, total_pages: @todos.total_pages } }
%ul.content-list.todos-list
= render @todos
= paginate @todos, theme: "gitlab"
.js-nothing-here-container.todos-all-done.hidden.svg-content
= image_tag 'illustrations/todos_all_done.svg'
%h4.text-center
You're all done!
.js-nothing-here-container.empty-state.hidden
.svg-content
= image_tag 'illustrations/todos_all_done.svg'
.text-content
%h4.text-center
You're all done!
- elsif current_user.todos.any?
.todos-all-done
.col.todos-all-done.empty-state
.svg-content.svg-250
= image_tag 'illustrations/todos_all_done.svg'
- if todos_filter_empty?
%h4.text-center
= Gitlab.config.gitlab.no_todos_messages.sample
%p
Are you looking for things to do? Take a look at
= succeed "," do
= link_to "open issues", issues_dashboard_path
contribute to
= link_to "a merge request\,", merge_requests_dashboard_path
or mention someone in a comment to automatically assign them a new to-do item.
- else
%h4.text-center
Nothing is on your to-do list. Nice work!
.text-content
- if todos_filter_empty?
%h4.text-center
= Gitlab.config.gitlab.no_todos_messages.sample
%p
Are you looking for things to do? Take a look at
= succeed "," do
%strong
= link_to "open issues", issues_dashboard_path
contribute to
%strong
= link_to "a merge request\,", merge_requests_dashboard_path
or mention someone in a comment to automatically assign them a new to-do item.
- else
%h4.text-center
Nothing is on your to-do list. Nice work!
- else
.todos-empty
.todos-empty-hero.svg-content
.col.empty-state
.svg-content
= image_tag 'illustrations/todos_empty.svg'
.todos-empty-content.gl-mx-5
%h4
.text-content
%h4.text-center
Your To-Do List shows what to work on next
%p
When an issue or merge request is assigned to you, or when you receive a
......
......@@ -79,7 +79,7 @@ RSpec.describe 'Dashboard Todos' do
end
it 'has not "All done" message' do
expect(page).not_to have_selector('.todos-all-done')
expect(page).not_to have_selector('.empty-state')
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment