From 7fa0b244e001954c2cfab1e84834de1bf3a63f0f Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Wed, 28 Oct 2015 11:05:13 -0600 Subject: [PATCH 01/35] Don't include filter string in exception message --- app/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/model.php b/app/model.php index 08f64221..cd782662 100644 --- a/app/model.php +++ b/app/model.php @@ -105,7 +105,7 @@ function load($filter=NULL, array $options=NULL, $ttl=0) { } elseif(is_array($filter)) { return parent::load($filter, $options, $ttl); } - throw new Exception("$filter must be either int or array."); + throw new Exception("\$filter must be either int or array."); } /** From 71b230b331755e058da374666c7581ccd188df2e Mon Sep 17 00:00:00 2001 From: evolver Date: Wed, 28 Oct 2015 23:21:19 +0500 Subject: [PATCH 02/35] "New Issues" page title fix --- app/controller/issues.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controller/issues.php b/app/controller/issues.php index e574405e..0d71d6fd 100644 --- a/app/controller/issues.php +++ b/app/controller/issues.php @@ -390,7 +390,7 @@ public function add_selecttype($f3, $params) { $type = new \Model\Issue\Type; $f3->set("types", $type->find(null, null, $f3->get("cache_expire.db"))); - $f3->set("title", $f3->get("dist.new_n", $f3->get("dict.issue"))); + $f3->set("title", $f3->get("dict.new_n", $f3->get("dict.issues"))); $f3->set("menuitem", "new"); $this->_render("issues/new.html"); } From b652249de199b03b50db1d9352030aa62f365fb1 Mon Sep 17 00:00:00 2001 From: evolver Date: Wed, 28 Oct 2015 23:34:28 +0500 Subject: [PATCH 03/35] Issue fields translation typos --- app/dict/ru.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/dict/ru.ini b/app/dict/ru.ini index 316fc8ab..a4e571d0 100644 --- a/app/dict/ru.ini +++ b/app/dict/ru.ini @@ -105,11 +105,11 @@ cols.type=Тип cols.priority=Приоритет cols.status=Статус cols.author=Автор -cols.assignee=Назначен на -cols.total_spent_hours=Всего Провел Часов -cols.hours_total=Планируемо Часов -cols.hours_remaining=Осталось Часов -cols.start_date=Start Date +cols.assignee=Назначено +cols.total_spent_hours=Всего затрачено часов +cols.hours_total=Планируется часов +cols.hours_remaining=Осталось часов +cols.start_date=Дата начала cols.due_date=Срок cols.repeat_cycle=Цикл повтора cols.parent_id=Родительский ID From 2c250bb46b8bcaf279eef4336c20138ca4cf4eaa Mon Sep 17 00:00:00 2001 From: evolver Date: Thu, 29 Oct 2015 00:43:57 +0500 Subject: [PATCH 04/35] Don't create watcher's duplicates when adding the same user --- app/controller/issues.php | 8 ++++++-- app/view/issues/single.html | 18 +++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/controller/issues.php b/app/controller/issues.php index 0d71d6fd..eefe9a97 100644 --- a/app/controller/issues.php +++ b/app/controller/issues.php @@ -628,13 +628,17 @@ public function single($f3, $params) { case "add_watcher": $watching = new \Model\Issue\Watcher; // Loads just in case the user is already a watcher - $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $post["user_id"])); + $watching_load_result = $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $post["user_id"])); $watching->issue_id = $issue->id; $watching->user_id = $post["user_id"]; $watching->save(); - if($f3->get("AJAX")) + if($f3->get("AJAX")) { + if(is_object($watching_load_result)) { + $this->_printJson(array("error" => 1)); + } return; + } break; case "remove_watcher": diff --git a/app/view/issues/single.html b/app/view/issues/single.html index 6c7ac506..56762f84 100644 --- a/app/view/issues/single.html +++ b/app/view/issues/single.html @@ -452,15 +452,19 @@ }); $('#add-watcher').submit(function(e) { $this = $(this); - $.post(BASE + '/issues/{{ @issue.id }}', $this.serialize()); + $.post(BASE + '/issues/{{ @issue.id }}', $this.serialize(), function(data) { + if(data && data.error) { + return; + } - $select = $this.find('select'); - $('
  • ') - .attr('data-user-id', $select.val()) - .html(' ' + $select.children('option:selected').text()) - .appendTo('#watchers-list'); + $select = $this.find('select'); + $('
  • ') + .attr('data-user-id', $select.val()) + .html(' ' + $select.children('option:selected').text()) + .appendTo('#watchers-list'); - $('#watchers-badge').text(parseInt($('#watchers-badge').text()) + 1); + $('#watchers-badge').text(parseInt($('#watchers-badge').text()) + 1); + }); e.preventDefault(); }); From fdc709cb065f57ef15e850b76ecb73e1ea233463 Mon Sep 17 00:00:00 2001 From: evolver Date: Thu, 29 Oct 2015 23:40:44 +0500 Subject: [PATCH 05/35] fix undefined variable --- app/controller/issues.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controller/issues.php b/app/controller/issues.php index 0d71d6fd..12427d29 100644 --- a/app/controller/issues.php +++ b/app/controller/issues.php @@ -604,7 +604,7 @@ public function save($f3, $params) { } } else { - $f3->reroute("/issues/new/" . $post["type_id"]); + $f3->reroute("/issues/new/" . $f3->get("POST.type_id")); } } From 68b1c4e464a01bb6ea94db93718cfbb668409aaa Mon Sep 17 00:00:00 2001 From: evolver Date: Fri, 30 Oct 2015 00:08:18 +0500 Subject: [PATCH 06/35] russian translations: Administration --- app/dict/ru.ini | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/dict/ru.ini b/app/dict/ru.ini index a4e571d0..cc772585 100644 --- a/app/dict/ru.ini +++ b/app/dict/ru.ini @@ -249,32 +249,32 @@ previous_sprints=Show Previous Sprints future_sprints=Show Future Sprints ; Administration -overview=Overview -new_user=New User -edit_user=Edit User -require_new_password=Require a new password on next login -role=Role -user=User -deactivate=Deactivate -reactivate=Reactivate -administrator=Administrator -members=Members -group_name=Group Name -group_name_saved=Group name saved -manager=Manager -set_as_manager=Set as Manager -add_to_group=Add to Group -no_groups_exist=No groups exist. -new_sprint=New Sprint -edit_sprint=Edit Sprint -start_date=Start Date -end_date=End Date -version=Version -current_version=Current Version +overview=Обзор +new_user=Новый пользователь +edit_user=Редактирование пользователя +require_new_password=Требовать новый пароль при следующем входе +role=Роль +user=Пользователь +deactivate=Отключить +reactivate=Восстановить +administrator=Администратор +members=Пользователи группы +group_name=Название группы +group_name_saved=Название группы сохранено +manager=Менеджер +set_as_manager=Назначить менеджером +add_to_group=Добавить в группу +no_groups_exist=Группы еще не созданы +new_sprint=Новый спринт +edit_sprint=Редактирование спринта +start_date=Дата начала +end_date=Дата окончания +version=Версия +current_version=Текущая версия update_available=Update Available update_to_n=Update to {0} backup_db=Are you sure?\nYou should back up your database before you proceed. -show_deactivated_users=Show Deactivated Users +show_deactivated_users=Показать отключенных пользователей ; User Ranks rank=Rank From bcbeac8e4a3aebb8a631bb0d3509ae52e198e864 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Thu, 29 Oct 2015 16:00:10 -0600 Subject: [PATCH 07/35] Fix error saving issue without a defined status --- app/model/issue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/model/issue.php b/app/model/issue.php index 7e2ff0f5..cec493b2 100644 --- a/app/model/issue.php +++ b/app/model/issue.php @@ -323,7 +323,7 @@ public function save($notify = true) { } else { // Set closed date if status is closed - if(!$this->closed_date) { + if(!$this->closed_date && $this->status) { $status = new Issue\Status; $status->load($this->status); if($status->closed) { From 0594e3d4c8b5ba5c8acfaa90f808369c180655a7 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Thu, 29 Oct 2015 16:02:34 -0600 Subject: [PATCH 08/35] Properly set status on new issues created via POST /issues.json --- app/controller/api/issues.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controller/api/issues.php b/app/controller/api/issues.php index 295899ee..a772549a 100644 --- a/app/controller/api/issues.php +++ b/app/controller/api/issues.php @@ -196,6 +196,7 @@ public function post($f3) { $issue->name = trim($post["name"]); $issue->type_id = empty($post["type_id"]) ? 1 : $post["type_id"]; $issue->priority_id = empty($post["priority_id"]) ? $f3->get("issue_priority.default") : $post["priority_id"]; + $issue->status = empty($status) ? 1 : $status->id; // Set due date if valid if(!empty($post["due_date"]) && preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}( [0-9:]{8})?$/", $post["due_date"])) { From 8f3de1ec11b7524653039ea0131d89c95edb2663 Mon Sep 17 00:00:00 2001 From: evolver Date: Fri, 30 Oct 2015 22:56:54 +0500 Subject: [PATCH 09/35] russian translations --- app/dict/ru.ini | 20 ++++++++++---------- app/view/admin/plugins.html | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/dict/ru.ini b/app/dict/ru.ini index cc772585..c1aacc84 100644 --- a/app/dict/ru.ini +++ b/app/dict/ru.ini @@ -40,8 +40,8 @@ dashboard=Панель issues=Задачи my_issues=Мои задачи my_account=Мой аккаунт -configuration=Configuration -plugins=Plugins +configuration=Настройки +plugins=Плагины users=Пользователи groups=Группы log_out=Выход @@ -81,7 +81,7 @@ issue_tree=Issue Tree name=Имя theme=Тема language=Язык -task_color=Цвет Задач +task_color=Цвет задач avatar=Аватар edit_on_gravatar=Редактировать из Gravatar save=Сохранить @@ -292,15 +292,15 @@ rank_permissions.4=Can create/edit/delete users/groups/sprints rank_permissions.5=Can edit configuration ; Config -site_basics=Site Basics -text_parsing=Text Parsing +site_basics=Основное +text_parsing=Парсинг текста email_smtp_imap=Email (SMTP/IMAP) -advanced=Advanced -site_name=Site Name -site_description=Site Description -timezone=Timezone +advanced=Прочее +site_name=Название сайта +site_description=Описание сайта +timezone=Часовой пояс default_theme=Тема по умолчанию -logo=Logo +logo=Логотип allow_public_registration=Allow public registration parser_syntax=Parser Syntax advanced_options=Advanced Options (all enabled by default) diff --git a/app/view/admin/plugins.html b/app/view/admin/plugins.html index 8cc083e4..8f21aafa 100644 --- a/app/view/admin/plugins.html +++ b/app/view/admin/plugins.html @@ -13,7 +13,7 @@ {{ @dict.name }} {{ @dict.cols.author }} - Version + {{ @dict.version }} From d32e9f4ff29ccb1e3733a85834f6ac27a78c001d Mon Sep 17 00:00:00 2001 From: evolver Date: Fri, 30 Oct 2015 23:10:39 +0500 Subject: [PATCH 10/35] russian translations --- app/dict/ru.ini | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/dict/ru.ini b/app/dict/ru.ini index c1aacc84..c17025df 100644 --- a/app/dict/ru.ini +++ b/app/dict/ru.ini @@ -49,7 +49,7 @@ demo_notice=Сайт работает в демонстрационном реж loading=Загрузка… close=Закрыть related=Related -current_issue=Current issue +current_issue=Текущая задача toggle_navigation=Toggle Navigation ; Errors @@ -119,7 +119,7 @@ cols.created=Создан cols.start=Start cols.due=Срок cols.closed_date=Closed -cols.hours_spent=Hours Spent +cols.hours_spent=Часов затрачено cols.depends_on=Depends On ; Issue editing @@ -180,13 +180,13 @@ a_changed_from_b_to_c={0} changed from {1} to {2} a_set_to_b={0} set to {1} a_removed={0} removed -dependencies=Dependencies -dependency=Dependency -dependent=Dependent -task_depends=This task depends on: -add_dependency=Add Dependency -task_dependency=This task is a dependency for: -add_dependent=Add Dependent +dependencies=Зависимости +dependency=Зависимость +dependent=Зависимый +task_depends=Эта задача зависит от: +add_dependency=Добавить зависимость +task_dependency=Эта задача является зависимостью для: +add_dependent=Добавить зависимого ; Dependency Types (Finish-Start, Finish-Finish, Start-Start, Start-Finish) fs=FS @@ -217,9 +217,9 @@ comment_delete_confirm=Вы точно хотите удалить этот ко bulk_actions=Показать все действия bulk_update=Обновить все выбранные задачи -project_overview=Project Overview -project_tree=Project Tree -n_complete={0} complete +project_overview=Обзор проекта +project_tree=Дерево проекта +n_complete={0} завершено n_child_issues={0} child issues ; Tags From beb5d8587ce387a179a4cbbcc38d4811cedfa7cd Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Sat, 31 Oct 2015 14:22:56 -0600 Subject: [PATCH 11/35] Adding working dashboard widget arrangement, new modules coming next --- app/controller/user.php | 9 ++ app/routes.ini | 1 + app/view/blocks/dashboard-issue-list.html | 3 + app/view/user/dashboard-widgets/bugs.html | 7 ++ app/view/user/dashboard-widgets/projects.html | 7 ++ .../user/dashboard-widgets/repeat-work.html | 5 ++ .../user/dashboard-widgets/subprojects.html | 5 ++ app/view/user/dashboard-widgets/tasks.html | 14 +++ .../user/dashboard-widgets/watchlist.html | 5 ++ app/view/user/dashboard.html | 90 +++++++++---------- css/style.css | 7 ++ 11 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 app/view/user/dashboard-widgets/bugs.html create mode 100644 app/view/user/dashboard-widgets/projects.html create mode 100644 app/view/user/dashboard-widgets/repeat-work.html create mode 100644 app/view/user/dashboard-widgets/subprojects.html create mode 100644 app/view/user/dashboard-widgets/tasks.html create mode 100644 app/view/user/dashboard-widgets/watchlist.html diff --git a/app/controller/user.php b/app/controller/user.php index 8434d1ae..0a3babb5 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -95,10 +95,19 @@ public function dashboard($f3, $params) { $sprint->load(array("? BETWEEN start_date AND end_date", date("Y-m-d"))); $f3->set("sprint", $sprint); + $f3->set("dashboard", $f3->get("user_obj")->option("dashboard") ?: array("left" => array("projects", "subprojects", "bugs", "repeat-work", "watchlist"), "right" => array("tasks"))); $f3->set("menuitem", "index"); $this->_render("user/dashboard.html"); } + public function dashboardPost($f3) { + $user = $f3->get("user_obj"); + $widgets = json_decode($f3->get("POST.widgets")); + $user->option('dashboard', $widgets); + $user->save(); + $this->_printJson($widgets); + } + private function _loadThemes() { $f3 = \Base::instance(); diff --git a/app/routes.ini b/app/routes.ini index 49fe8c01..7996791b 100644 --- a/app/routes.ini +++ b/app/routes.ini @@ -49,6 +49,7 @@ GET /user = Controller\User->account POST /user = Controller\User->save POST /user/avatar = Controller\User->avatar GET /user/dashboard = Controller\User->dashboard +POST /user/dashboard = Controller\User->dashboardPost GET /user/@username = Controller\User->single GET /user/@username/tree = Controller\User->single_tree GET /user/@username/overdue = Controller\User->single_overdue diff --git a/app/view/blocks/dashboard-issue-list.html b/app/view/blocks/dashboard-issue-list.html index 1d2a0610..a4cf8357 100644 --- a/app/view/blocks/dashboard-issue-list.html +++ b/app/view/blocks/dashboard-issue-list.html @@ -39,4 +39,7 @@ + +
  • No matching issues
  • + diff --git a/app/view/user/dashboard-widgets/bugs.html b/app/view/user/dashboard-widgets/bugs.html new file mode 100644 index 00000000..c1e8a482 --- /dev/null +++ b/app/view/user/dashboard-widgets/bugs.html @@ -0,0 +1,7 @@ +
    +

    {{ @dict.my_bugs }} {{ count(@bugs) }}  + +

    + + +
    diff --git a/app/view/user/dashboard-widgets/projects.html b/app/view/user/dashboard-widgets/projects.html new file mode 100644 index 00000000..9f20d0f2 --- /dev/null +++ b/app/view/user/dashboard-widgets/projects.html @@ -0,0 +1,7 @@ +
    +

    {{ @dict.my_projects }} {{ count(@projects) }}  + +

    + + +
    diff --git a/app/view/user/dashboard-widgets/repeat-work.html b/app/view/user/dashboard-widgets/repeat-work.html new file mode 100644 index 00000000..81be487a --- /dev/null +++ b/app/view/user/dashboard-widgets/repeat-work.html @@ -0,0 +1,5 @@ +
    +

    {{ @dict.repeat_work }} {{ count(@repeat_issues) }}

    + + +
    diff --git a/app/view/user/dashboard-widgets/subprojects.html b/app/view/user/dashboard-widgets/subprojects.html new file mode 100644 index 00000000..e8483626 --- /dev/null +++ b/app/view/user/dashboard-widgets/subprojects.html @@ -0,0 +1,5 @@ +
    +

    {{ @dict.my_subprojects }} {{ count(@subprojects) }}

    + + +
    diff --git a/app/view/user/dashboard-widgets/tasks.html b/app/view/user/dashboard-widgets/tasks.html new file mode 100644 index 00000000..85a5539f --- /dev/null +++ b/app/view/user/dashboard-widgets/tasks.html @@ -0,0 +1,14 @@ +
    +
    + + + +

    {{ @dict.my_tasks }} {{ count(@tasks) }}  + +

    +
    + + +
    diff --git a/app/view/user/dashboard-widgets/watchlist.html b/app/view/user/dashboard-widgets/watchlist.html new file mode 100644 index 00000000..063c0a35 --- /dev/null +++ b/app/view/user/dashboard-widgets/watchlist.html @@ -0,0 +1,5 @@ +
    +

    {{ @dict.my_watchlist }} {{ count(@watchlist) }}

    + + +
    diff --git a/app/view/user/dashboard.html b/app/view/user/dashboard.html index 1a1b1c0f..27af26c2 100644 --- a/app/view/user/dashboard.html +++ b/app/view/user/dashboard.html @@ -11,57 +11,55 @@ -
    +
    -
    -

    {{ @dict.my_projects }} {{ count(@projects) }}  - -

    - - - - -

    {{ @dict.my_subprojects }} {{ count(@subprojects) }}

    - - -
    - - -

    {{ @dict.my_bugs }} {{ count(@bugs) }}  - -

    - - - - - -

    {{ @dict.repeat_work }} {{ count(@repeat_issues) }}

    - - -
    - - -

    {{ @dict.my_watchlist }} {{ count(@watchlist) }}

    - - -
    +
    + + +
    -
    -
    -

    {{ @dict.my_tasks }} {{ count(@tasks) }}  - -

    - - - -
    - - +
    + + +
    + +
    diff --git a/css/style.css b/css/style.css index 7bcf2f74..b3f72fa5 100644 --- a/css/style.css +++ b/css/style.css @@ -69,6 +69,13 @@ a.nolink:hover { .dashboard .list-group-item .badge-sibling { margin: 2px 10px 0 0; } +.dashboard-widget-box { + min-height: 300px; + padding-bottom: 100px; +} +.dashboard-widget-handle { + cursor: move; +} textarea { resize: vertical; From 57f5e9964ef21097891709c4a6d2464ea4c7c28c Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Sat, 31 Oct 2015 21:27:49 -0600 Subject: [PATCH 12/35] Moving dashboard data loading to helper class functions --- app/controller/user.php | 70 +++---------- app/helper/dashboard.php | 99 +++++++++++++++++++ .../{repeat-work.html => repeat_work.html} | 4 +- 3 files changed, 113 insertions(+), 60 deletions(-) create mode 100644 app/helper/dashboard.php rename app/view/user/dashboard-widgets/{repeat-work.html => repeat_work.html} (65%) diff --git a/app/controller/user.php b/app/controller/user.php index 0a3babb5..c20d01f5 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -28,74 +28,28 @@ public function index($f3) { } public function dashboard($f3, $params) { - $issue = new \Model\Issue\Detail(); - - // Add user's group IDs to owner filter - $owner_ids = array($this->_userId); - $groups = new \Model\User\Group(); - foreach($groups->find(array("user_id = ?", $this->_userId)) as $r) { - $owner_ids[] = $r->group_id; + $dashboard = $f3->get("user_obj")->option("dashboard"); + if(!$dashboard) { + $dashboard = array( + "left" => array("projects", "subprojects", "bugs", "repeat_work", "watchlist"), + "right" => array("tasks") + ); } - $owner_ids = implode(",", $owner_ids); - - $order = "priority DESC, has_due_date ASC, due_date ASC"; - $projects = $issue->find( - array( - "owner_id IN ($owner_ids) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", - ":type" => $f3->get("issue_type.project"), - ),array( - "order" => $order - ) - ); - $subprojects = array(); - foreach($projects as $i=>$project) { - if($project->parent_id) { - $subprojects[] = $project; - unset($projects[$i]); + // Load dashboard widget data + $helper = \Helper\Dashboard::instance(); + foreach($dashboard as $pos=>$widgets) { + foreach($widgets as $widget) { + $f3->set($widget, $helper->$widget()); } } - $f3->set("projects", $projects); - $f3->set("subprojects", $subprojects); - - $f3->set("bugs", $issue->find( - array( - "owner_id IN ($owner_ids) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", - ":type" => $f3->get("issue_type.bug"), - ),array( - "order" => $order - ) - )); - - $f3->set("repeat_issues", $issue->find( - array( - "owner_id IN ($owner_ids) AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0 AND repeat_cycle NOT IN ('none', '')", - ":type" => $f3->get("issue_type.bug"), - ),array( - "order" => $order - ) - )); - - $watchlist = new \Model\Issue\Watcher(); - $f3->set("watchlist", $watchlist->findby_watcher($this->_userId, $order)); - - - $tasks = new \Model\Issue\Detail(); - $f3->set("tasks", $tasks->find( - array( - "owner_id IN ($owner_ids) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", - ":type" => $f3->get("issue_type.task"), - ),array( - "order" => $order - ) - )); // Get current sprint if there is one $sprint = new \Model\Sprint; $sprint->load(array("? BETWEEN start_date AND end_date", date("Y-m-d"))); $f3->set("sprint", $sprint); - $f3->set("dashboard", $f3->get("user_obj")->option("dashboard") ?: array("left" => array("projects", "subprojects", "bugs", "repeat-work", "watchlist"), "right" => array("tasks"))); + $f3->set("dashboard", $dashboard); $f3->set("menuitem", "index"); $this->_render("user/dashboard.html"); } diff --git a/app/helper/dashboard.php b/app/helper/dashboard.php new file mode 100644 index 00000000..2080b07b --- /dev/null +++ b/app/helper/dashboard.php @@ -0,0 +1,99 @@ +_issue === null ? $this->_issue = new \Model\Issue\Detail : $this->_issue; + } + + public function getOwnerIds() { + if($this->_ownerIds) { + return $this->_ownerIds; + } + $f3 = \Base::instance(); + $this->_ownerIds = array($f3->get("user.id")); + $groups = new \Model\User\Group(); + foreach($groups->find(array("user_id = ?", $f3->get("user.id"))) as $r) { + $this->_ownerIds[] = $r->group_id; + } + return $this->_ownerIds; + } + + public function projects() { + $f3 = \Base::instance(); + $ownerString = implode(",", $this->getOwnerIds()); + $this->_projects = $this->getIssue()->find( + array( + "owner_id IN ($ownerString) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", + ":type" => $f3->get("issue_type.project"), + ), + array("order" => $this->_order) + ); + return $this->_projects; + } + + public function subprojects() { + if($this->_projects === null) { + $this->projects(); + } + + $projects = $this->_projects; + $subprojects = array(); + foreach($projects as $i=>$project) { + if($project->parent_id) { + $subprojects[] = $project; + unset($projects[$i]); + } + } + + return $subprojects; + } + + public function bugs() { + $f3 = \Base::instance(); + $ownerString = implode(",", $this->getOwnerIds()); + return $this->getIssue()->find( + array( + "owner_id IN ($ownerString) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", + ":type" => $f3->get("issue_type.bug"), + ), + array("order" => $this->_order) + ); + } + + public function repeat_work() { + $ownerString = implode(",", $this->getOwnerIds()); + return $this->getIssue()->find( + "owner_id IN ($ownerString) AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0 AND repeat_cycle NOT IN ('none', '')", + array("order" => $this->_order) + ); + } + + public function watchlist() { + $f3 = \Base::instance(); + $watchlist = new \Model\Issue\Watcher(); + return $watchlist->findby_watcher($f3->get("user.id"), $this->_order); + } + + public function tasks() { + $f3 = \Base::instance(); + $ownerString = implode(",", $this->getOwnerIds()); + return $this->getIssue()->find( + array( + "owner_id IN ($ownerString) AND type_id=:type AND deleted_date IS NULL AND closed_date IS NULL AND status_closed = 0", + ":type" => $f3->get("issue_type.task"), + ), + array("order" => $this->_order) + ); + } + +} diff --git a/app/view/user/dashboard-widgets/repeat-work.html b/app/view/user/dashboard-widgets/repeat_work.html similarity index 65% rename from app/view/user/dashboard-widgets/repeat-work.html rename to app/view/user/dashboard-widgets/repeat_work.html index 81be487a..82c0f833 100644 --- a/app/view/user/dashboard-widgets/repeat-work.html +++ b/app/view/user/dashboard-widgets/repeat_work.html @@ -1,5 +1,5 @@
    -

    {{ @dict.repeat_work }} {{ count(@repeat_issues) }}

    - +

    {{ @dict.repeat_work }} {{ count(@repeat_work) }}

    +
    From 2be3d5baba2d369e8bfdf88dadf7587a57701340 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Sat, 31 Oct 2015 23:16:06 -0600 Subject: [PATCH 13/35] Working widget adding/removing --- app/controller/user.php | 20 +++++- app/helper/dashboard.php | 1 - .../user/dashboard-widgets/repeat_work.html | 2 +- app/view/user/dashboard-widgets/tasks.html | 13 +--- app/view/user/dashboard.html | 62 ++++++++++++++++++- css/style.css | 16 +++++ 6 files changed, 96 insertions(+), 18 deletions(-) diff --git a/app/controller/user.php b/app/controller/user.php index c20d01f5..4302a9b7 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -37,12 +37,15 @@ public function dashboard($f3, $params) { } // Load dashboard widget data + $allWidgets = array("projects", "subprojects", "tasks", "bugs", "repeat_work", "watchlist"); $helper = \Helper\Dashboard::instance(); foreach($dashboard as $pos=>$widgets) { foreach($widgets as $widget) { $f3->set($widget, $helper->$widget()); + unset($allWidgets[array_search($widget, $allWidgets)]); } } + $f3->set("unused_widgets", $allWidgets); // Get current sprint if there is one $sprint = new \Model\Sprint; @@ -56,10 +59,21 @@ public function dashboard($f3, $params) { public function dashboardPost($f3) { $user = $f3->get("user_obj"); - $widgets = json_decode($f3->get("POST.widgets")); - $user->option('dashboard', $widgets); + if($f3->get("POST.action") == "add") { + $widgets = $user->option("dashboard"); + foreach($f3->get("POST.widgets") as $widget) { + $widgets["left"][] = $widget; + } + } else { + $widgets = json_decode($f3->get("POST.widgets")); + } + $user->option("dashboard", $widgets); $user->save(); - $this->_printJson($widgets); + if($f3->get("AJAX")) { + $this->_printJson($widgets); + } else { + $f3->reroute("/"); + } } private function _loadThemes() { diff --git a/app/helper/dashboard.php b/app/helper/dashboard.php index 2080b07b..bb450e20 100644 --- a/app/helper/dashboard.php +++ b/app/helper/dashboard.php @@ -4,7 +4,6 @@ class Dashboard extends \Prefab { - protected $_issue, $_ownerIds, diff --git a/app/view/user/dashboard-widgets/repeat_work.html b/app/view/user/dashboard-widgets/repeat_work.html index 82c0f833..e40cfa27 100644 --- a/app/view/user/dashboard-widgets/repeat_work.html +++ b/app/view/user/dashboard-widgets/repeat_work.html @@ -1,4 +1,4 @@ -
    +

    {{ @dict.repeat_work }} {{ count(@repeat_work) }}

    diff --git a/app/view/user/dashboard-widgets/tasks.html b/app/view/user/dashboard-widgets/tasks.html index 85a5539f..06d20f79 100644 --- a/app/view/user/dashboard-widgets/tasks.html +++ b/app/view/user/dashboard-widgets/tasks.html @@ -1,14 +1,7 @@
    -
    - - - -

    {{ @dict.my_tasks }} {{ count(@tasks) }}  - -

    -
    +

    {{ @dict.my_tasks }} {{ count(@tasks) }}  + +

    diff --git a/app/view/user/dashboard.html b/app/view/user/dashboard.html index 27af26c2..29b33aff 100644 --- a/app/view/user/dashboard.html +++ b/app/view/user/dashboard.html @@ -12,6 +12,16 @@
    + + +  Add Widgets + + + +  {{ @dict.taskboard }} + + +
    @@ -24,14 +34,46 @@
    + + +
    diff --git a/css/style.css b/css/style.css index b3f72fa5..206a916c 100644 --- a/css/style.css +++ b/css/style.css @@ -74,8 +74,24 @@ a.nolink:hover { padding-bottom: 100px; } .dashboard-widget-handle { + position: relative; cursor: move; } +.dashboard-widget-handle .close { + position: absolute; + top: 5px; + right: 5px; + color: inherit; + visibility: hidden; +} +.dashboard-widget:hover .dashboard-widget-handle .close { + visibility: visible; +} +@media screen and (max-width: 767px) { + .dashboard-widget-handle .close { + visibility: visible; + } +} textarea { resize: vertical; From 399ada5d6f4e0bfeab3f6ba4458dd6cfac0cc2e5 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Sat, 31 Oct 2015 23:54:35 -0600 Subject: [PATCH 14/35] Adding my_comments and recent_comments dashboard widgets --- app/controller/user.php | 8 +++-- app/dict/en.ini | 2 ++ app/helper/dashboard.php | 22 ++++++++++++++ app/view/blocks/issue-comment.html | 30 +++++++++++++++++++ app/view/issues/single.html | 28 +---------------- .../user/dashboard-widgets/my_comments.html | 10 +++++++ .../dashboard-widgets/recent_comments.html | 10 +++++++ 7 files changed, 81 insertions(+), 29 deletions(-) create mode 100644 app/view/blocks/issue-comment.html create mode 100644 app/view/user/dashboard-widgets/my_comments.html create mode 100644 app/view/user/dashboard-widgets/recent_comments.html diff --git a/app/controller/user.php b/app/controller/user.php index 4302a9b7..467dffa2 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -37,11 +37,15 @@ public function dashboard($f3, $params) { } // Load dashboard widget data - $allWidgets = array("projects", "subprojects", "tasks", "bugs", "repeat_work", "watchlist"); + $allWidgets = array("projects", "subprojects", "tasks", "bugs", "repeat_work", "watchlist", "my_comments", "recent_comments"); $helper = \Helper\Dashboard::instance(); foreach($dashboard as $pos=>$widgets) { foreach($widgets as $widget) { - $f3->set($widget, $helper->$widget()); + if(is_callable(array($helper, $widget))) { + $f3->set($widget, $helper->$widget()); + } else { + $f3->set("error", "Widget '{$widget}' is not available."); + } unset($allWidgets[array_search($widget, $allWidgets)]); } } diff --git a/app/dict/en.ini b/app/dict/en.ini index d869a005..851fd940 100644 --- a/app/dict/en.ini +++ b/app/dict/en.ini @@ -70,6 +70,8 @@ my_watchlist=My Watch List add_project=Add Project add_task=Add Task add_bug=Add Bug +my_comments=My Comments +recent_comments=Recent Comments ; User pages created_issues=Created Issues diff --git a/app/helper/dashboard.php b/app/helper/dashboard.php index bb450e20..8bba5342 100644 --- a/app/helper/dashboard.php +++ b/app/helper/dashboard.php @@ -95,4 +95,26 @@ public function tasks() { ); } + public function my_comments() { + $f3 = \Base::instance(); + $comment = new \Model\Issue\Comment\Detail; + return $comment->find(array("user_id = ?", $f3->get("user.id")), array("order" => "created_date DESC", "limit" => 10)); + } + + public function recent_comments() { + $f3 = \Base::instance(); + + $issue = new \Model\Issue; + $ownerString = implode(",", $this->getOwnerIds()); + $issues = $issue->find(array("owner_id IN ($ownerString) OR author_id = ?", $f3->get("user.id"))); + $ids = array(); + foreach($issues as $item) { + $ids[] = $item->id; + } + + $comment = new \Model\Issue\Comment\Detail; + $issueIds = implode(",", $ids); + return $comment->find(array("issue_id IN ($issueIds) AND user_id != ?", $f3->get("user.id")), array("order" => "created_date DESC", "limit" => 15)); + } + } diff --git a/app/view/blocks/issue-comment.html b/app/view/blocks/issue-comment.html new file mode 100644 index 00000000..a1df492e --- /dev/null +++ b/app/view/blocks/issue-comment.html @@ -0,0 +1,30 @@ +
    + + + +
    +

    + {{ @comment.user_name }} + + > {{ @issue.name }} + + + × + +

    +
    {{ @comment.text, array('hashtags' => false) | parseText }}
    + + + +
    {{ @dict.attached_file }}: {{ @comment.file_filename | esc }} [{{ @dict.deleted }}]
    +
    + +
    {{ @dict.attached_file }}: {{ @comment.file_filename | esc }}
    +
    +
    +
    +

    + {{ date("D, M j, Y \\a\\t g:ia", $this->utc2local(strtotime(@comment.created_date))) }} +

    +
    +
    diff --git a/app/view/issues/single.html b/app/view/issues/single.html index 6c7ac506..9d7ca4a6 100644 --- a/app/view/issues/single.html +++ b/app/view/issues/single.html @@ -258,33 +258,7 @@

    -
    - - - -
    -

    - {{ @comment.user_name }} - - × - -

    -
    {{ @comment.text, array('hashtags' => false) | parseText }}
    - - - -
    {{ @dict.attached_file }}: {{ @comment.file_filename | esc }} [{{ @dict.deleted }}]
    -
    - -
    {{ @dict.attached_file }}: {{ @comment.file_filename | esc }}
    -
    -
    -
    -

    - {{ date("D, M j, Y \\a\\t g:ia", $this->utc2local(strtotime(@comment.created_date))) }} -

    -
    -
    +
    diff --git a/app/view/user/dashboard-widgets/my_comments.html b/app/view/user/dashboard-widgets/my_comments.html new file mode 100644 index 00000000..a3140c5d --- /dev/null +++ b/app/view/user/dashboard-widgets/my_comments.html @@ -0,0 +1,10 @@ +
    +

    {{ @dict.my_comments }}

    +
    + {~ @issue = new \Model\Issue() ~} + + {~ @issue->load(@comment.issue_id) ~} + + +
    +
    diff --git a/app/view/user/dashboard-widgets/recent_comments.html b/app/view/user/dashboard-widgets/recent_comments.html new file mode 100644 index 00000000..6ef4d61a --- /dev/null +++ b/app/view/user/dashboard-widgets/recent_comments.html @@ -0,0 +1,10 @@ +
    +

    {{ @dict.recent_comments }}

    +
    + {~ @issue = new \Model\Issue() ~} + + {~ @issue->load(@comment.issue_id) ~} + + +
    +
    From 05fb163d312b2efbdc7a8de451b206c9b67777c1 Mon Sep 17 00:00:00 2001 From: evolver Date: Mon, 2 Nov 2015 22:29:58 +0500 Subject: [PATCH 15/35] russian translations --- app/dict/ru.ini | 54 +++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/app/dict/ru.ini b/app/dict/ru.ini index c17025df..dc71d5e2 100644 --- a/app/dict/ru.ini +++ b/app/dict/ru.ini @@ -1,6 +1,6 @@ ; Index, login, password reset log_in=Вход -register=Register +register=Регистрация username=Логин password=Пароль email=Email @@ -56,15 +56,15 @@ toggle_navigation=Toggle Navigation error.loading_issue_history=Ошибка загрузки истории задачи. error.loading_issue_watchers=Ошибка загрузки наблюдателей задачи. error.loading_related_issues=Ошибка загрузки связаных задач. -error.loading_dependencies=Error loading dependencies. -error.404_text=The page you requested is not available. +error.loading_dependencies=Ошибка загрузки зависимостей. +error.404_text=Запрошенная страница отсутствует. ; Dashboard taskboard=Панель задач -my_projects=Мои Проекты -my_subprojects=My Subprojects -my_tasks=Мои Задачи -my_bugs=Мои Проблемы +my_projects=Мои проекты +my_subprojects=Мои подпроекты +my_tasks=Мои задачи +my_bugs=Мои баги repeat_work=Repeat Work my_watchlist=My Watch List add_project=Добавить проект @@ -72,10 +72,10 @@ add_task=Добавить Задачу add_bug=Добавить Проблему ; User pages -created_issues=Созданные Запросы -assigned_issues=Назначеные Запросы -overdue_issues=Overdue Issues -issue_tree=Issue Tree +created_issues=Созданные задачи +assigned_issues=Назначеные задачи +overdue_issues=Просроченные задачи +issue_tree=Дерево задач ; Account name=Имя @@ -86,8 +86,10 @@ avatar=Аватар edit_on_gravatar=Редактировать из Gravatar save=Сохранить current_password=Текущий пароль -profile=Profile -default=Default +profile=Профиль +settings=Настройки +default=По умолчанию +disable_editor=Отключить редактор ; Browse general=Общее @@ -223,11 +225,11 @@ n_complete={0} завершено n_child_issues={0} child issues ; Tags -issue_tags=Issue Tags -no_tags_created=No issue tags have been created yet. -tag_help_1=Tag an issue by adding a #hashtag to its description. -tag_help_2=Hashtags can contain letters, numbers, and hyphens, and must start with a letter. -view_all_tags=View all tags +issue_tags=Теги задач +no_tags_created=Теги пока еще не созданы. +tag_help_1=Для создания тега задачи добавьте #хештег в ее описание. +tag_help_2=Хештеги могут содержать буквы, числа, и дефисы, а также должны начинаться с буквы. +view_all_tags=Все теги ; Taskboard/Backlog backlog=Backlog @@ -302,15 +304,15 @@ timezone=Часовой пояс default_theme=Тема по умолчанию logo=Логотип allow_public_registration=Allow public registration -parser_syntax=Parser Syntax -advanced_options=Advanced Options (all enabled by default) -convert_ids=Convert IDs to Links -convert_hashtags=Convert Hashtags to Links -convert_urls=Convert URLs to links +parser_syntax=Парсер синтаксиса +advanced_options=Дополнительные параметры (по умолчанию все включены) +convert_ids=Конвертировать ID в ссылки +convert_hashtags=Конвертировать Хештеги в ссылки +convert_urls=Конвертировать URL в ссылки convert_emoticons=Convert emoticons to glyphs -outgoing_mail=Outgoing Mail (SMTP) -from_address=From Address -incoming_mail=Incoming Mail (IMAP) +outgoing_mail=Исходящая почта (SMTP) +from_address=Адрес от кого +incoming_mail=Входящая почта (IMAP) hostname=Hostname debug_level=Debug Level (DEBUG) cache_mode=Cache Mode (CACHE) From 472f68efde23b7bd2ef97fb337ac4e7fbafdee1e Mon Sep 17 00:00:00 2001 From: evolver Date: Mon, 2 Nov 2015 22:47:39 +0500 Subject: [PATCH 16/35] navbar at single place --- app/view/blocks/navbar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/view/blocks/navbar.html b/app/view/blocks/navbar.html index 52c13263..a3810114 100644 --- a/app/view/blocks/navbar.html +++ b/app/view/blocks/navbar.html @@ -1,6 +1,6 @@