Merge branch 'add-todo-toggle-event' into 'master'

Add todo toggle event

## What does this MR do?
Adds a custom jQuery event `todo:toggle` to detect when a new todo is added so that the respective todo counters (header navigation and sidebar) can update as needed

## Are there points in the code the reviewer needs to double check?

*  I wasn't sure whether each `spec` should be modularized based on the html templates or whether they should be separated based on function. There are some crossovers between the `dashboard_spec` and the `header_spec`.
* The naming conventions for `sidebar` and `right_sidebar` were a little confusing since they were named the opposite in their `specs`. I made a few assumptions and named a few files based on what I thought they should be named. I'd be happy to change it to something else though 😄  

## Why was this MR needed?
This resolves an existing issue where the todo count on the sidebar would not update (until refresh) and refactors the existing methods that are used to update the todo counters (header navigation and sidebar)

## What are the relevant issue numbers?
Closes #20140

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

See merge request !5724
This commit is contained in:
Fatih Acet 2016-10-27 13:28:40 +00:00
commit f879319840
15 changed files with 223 additions and 13 deletions

View file

@ -102,6 +102,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Add more tests for calendar contribution (ClemMakesApps)
- Update Gitlab Shell to fix some problems with moving projects between storages
- Cache rendered markdown in the database, rather than Redis
- Add todo toggle event (ClemMakesApps)
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
- Simplify Mentionable concern instance methods
- API: Ability to retrieve version information (Robert Schilling)

View file

@ -0,0 +1,9 @@
(function() {
$(document).on('todo:toggle', function(e, count) {
var $todoPendingCount = $('.todos-pending-count');
$todoPendingCount.text(gl.text.addDelimiter(count));
$todoPendingCount.toggleClass('hidden', count === 0);
});
})();

View file

@ -8,6 +8,9 @@
if ((base = w.gl).text == null) {
base.text = {};
}
gl.text.addDelimiter = function(text) {
return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text;
}
gl.text.randomString = function() {
return Math.random().toString(36).substring(7);
};

View file

@ -82,16 +82,11 @@
};
Sidebar.prototype.todoUpdateDone = function(data, $btn, $btnText, $todoLoading) {
var $todoPendingCount;
$todoPendingCount = $('.todos-pending-count');
$todoPendingCount.text(data.count);
$(document).trigger('todo:toggle', data.count);
$btn.enable();
$todoLoading.addClass('hidden');
if (data.count === 0) {
$todoPendingCount.addClass('hidden');
} else {
$todoPendingCount.removeClass('hidden');
}
if (data.delete_path != null) {
$btn.attr('aria-label', $btn.data('mark-text')).attr('data-delete-path', data.delete_path);
return $btnText.text($btn.data('mark-text'));

View file

@ -38,7 +38,8 @@
.on('click', sidebarToggleSelector, () => this.toggleSidebar())
.on('click', pinnedToggleSelector, () => this.togglePinnedState())
.on('click', 'html, body', (e) => this.handleClickEvent(e))
.on('page:change', () => this.renderState());
.on('page:change', () => this.renderState())
.on('todo:toggle', (e, count) => this.updateTodoCount(count));
this.renderState();
}
@ -53,6 +54,10 @@
}
}
updateTodoCount(count) {
$('.js-todos-count').text(gl.text.addDelimiter(count));
}
toggleSidebar() {
this.isExpanded = !this.isExpanded;
this.renderState();

View file

@ -98,7 +98,8 @@
}
updateBadges(data) {
$('.todos-pending .badge, .todos-pending-count').text(data.count);
$(document).trigger('todo:toggle', data.count);
$('.todos-pending .badge').text(data.count);
return $('.todos-done .badge').text(data.done_count);
}

View file

@ -7,7 +7,7 @@
= link_to dashboard_todos_path, title: 'Todos' do
%span
Todos
%span.count= number_with_delimiter(todos_pending_count)
%span.count.js-todos-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
%span

View file

@ -132,7 +132,6 @@ describe 'Dashboard Todos', feature: true do
end
it 'shows "All done" message!' do
within('.todos-pending-count') { expect(page).to have_content '0' }
expect(page).to have_content 'To do 0'
expect(page).to have_content "You're all done!"
expect(page).not_to have_selector('.gl-pagination')

View file

@ -0,0 +1,38 @@
/*= require sidebar */
/*= require jquery */
/*= require jquery.cookie */
/*= require lib/utils/text_utility */
((global) => {
describe('Dashboard', () => {
const fixtureTemplate = 'dashboard.html';
function todosCountText() {
return $('.js-todos-count').text();
}
function triggerToggle(newCount) {
$(document).trigger('todo:toggle', newCount);
}
fixture.preload(fixtureTemplate);
beforeEach(() => {
fixture.load(fixtureTemplate);
new global.Sidebar();
});
it('should update todos-count after receiving the todo:toggle event', () => {
triggerToggle(5);
expect(todosCountText()).toEqual('5');
});
it('should display todos-count with delimiter', () => {
triggerToggle(1000);
expect(todosCountText()).toEqual('1,000');
triggerToggle(1000000);
expect(todosCountText()).toEqual('1,000,000');
});
});
})(window.gl);

View file

@ -0,0 +1,45 @@
%ul.nav.nav-sidebar
%li.home.active
%a.dashboard-shortcuts-projects
%span
Projects
%li
%a
%span
Todos
%span.count.js-todos-count
1
%li
%a.dashboard-shortcuts-activity
%span
Activity
%li
%a
%span
Groups
%li
%a
%span
Milestones
%li
%a.dashboard-shortcuts-issues
%span
Issues
%span
1
%li
%a.dashboard-shortcuts-merge_requests
%span
Merge Requests
%li
%a
%span
Snippets
%li
%a
%span
Help
%li
%a
%span
Profile Settings

View file

@ -0,0 +1,35 @@
%header.navbar.navbar-fixed-top.navbar-gitlab.nav_header_class
.container-fluid
.header-content
%button.side-nav-toggle
%span.sr-only
Toggle navigation
%i.fa.fa-bars
%button.navbar-toggle
%span.sr-only
Toggle navigation
%i.fa.fa-ellipsis-v
.navbar-collapse.collapse
%ui.nav.navbar-nav
%li.hidden-sm.hidden-xs
%li.visible-sm.visible-xs
%li
%a
%i.fa.fa-bell.fa-fw
%span.badge.todos-pending-count
%li
%a
%i.fa.fa-plus.fa-fw
%li.header-user.dropdown
%a
%img
%span.caret
.dropdown-menu-nav
.dropdown-menu-align-right
%ul
%li
%a.profile-link
%li
%a
%li.divider
%li.sign-out-link

View file

@ -5,6 +5,10 @@
%div.block.issuable-sidebar-header
%a.gutter-toggle.pull-right.js-sidebar-toggle
%i.fa.fa-angle-double-left
%button.btn.btn-default.issuable-header-btn.pull-right.js-issuable-todo{ type: "button", data: { todo_text: "Add Todo", mark_text: "Mark Done", issuable_id: "1", issuable_type: "issue", url: "/todos" }}
%span.js-issuable-todo-text
Add Todo
%i.fa.fa-spin.fa-spinner.js-issuable-todo-loading.hidden
%form.issuable-context-form
%div.block.labels

View file

@ -0,0 +1,4 @@
{
"count": 1,
"delete_path": "/dashboard/todos/1"
}

View file

@ -0,0 +1,54 @@
/*= require header */
/*= require lib/utils/text_utility */
/*= require jquery */
(function() {
describe('Header', function() {
var todosPendingCount = '.todos-pending-count';
var fixtureTemplate = 'header.html';
function isTodosCountHidden() {
return $(todosPendingCount).hasClass('hidden');
}
function triggerToggle(newCount) {
$(document).trigger('todo:toggle', newCount);
}
fixture.preload(fixtureTemplate);
beforeEach(function() {
fixture.load(fixtureTemplate);
});
it('should update todos-pending-count after receiving the todo:toggle event', function() {
triggerToggle(5);
expect($(todosPendingCount).text()).toEqual('5');
});
it('should hide todos-pending-count when it is 0', function() {
triggerToggle(0);
expect(isTodosCountHidden()).toEqual(true);
});
it('should show todos-pending-count when it is more than 0', function() {
triggerToggle(10);
expect(isTodosCountHidden()).toEqual(false);
});
describe('when todos-pending-count is 1000', function() {
beforeEach(function() {
triggerToggle(1000);
});
it('should show todos-pending-count', function() {
expect(isTodosCountHidden()).toEqual(false);
});
it('should add delimiter to todos-pending-count', function() {
expect($(todosPendingCount).text()).toEqual('1,000');
});
});
});
}).call(this);

View file

@ -4,6 +4,8 @@
/*= require jquery */
/*= require js.cookie */
/*= require extensions/jquery.js */
(function() {
var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState;
@ -56,12 +58,27 @@
$labelsIcon.click();
return assertSidebarState('expanded');
});
return it('should collapse when the icon arrow clicked while it is floating on page', function() {
it('should collapse when the icon arrow clicked while it is floating on page', function() {
$labelsIcon.click();
assertSidebarState('expanded');
$toggle.click();
return assertSidebarState('collapsed');
});
it('should broadcast todo:toggle event when add todo clicked', function() {
spyOn(jQuery, 'ajax').and.callFake(function() {
var d = $.Deferred();
var response = fixture.load('todos.json');
d.resolve(response);
return d.promise();
});
var todoToggleSpy = spyOnEvent(document, 'todo:toggle');
$('.js-issuable-todo').click();
expect(todoToggleSpy.calls.count()).toEqual(1);
})
});
}).call(this);